diff options
Diffstat (limited to 'source/blender/windowmanager')
19 files changed, 974 insertions, 463 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 088bddc8a76..78b5d499644 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -130,10 +130,10 @@ if(WITH_BUILDINFO) add_definitions(-DWITH_BUILDINFO) endif() -if(WIN322) - list(APPEND INC - ../../../intern/utfconv - ) +if(WIN32) + if(WITH_INPUT_IME) + add_definitions(-DWITH_INPUT_IME) + endif() endif() if(WITH_COMPOSITOR) diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript index b93192d5067..a6f64f7cdae 100644 --- a/source/blender/windowmanager/SConscript +++ b/source/blender/windowmanager/SConscript @@ -65,11 +65,14 @@ if env['WITH_BF_COLLADA']: if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'): incs += ' ' + env['BF_PTHREADS_INC'] - incs += ' ../../intern/utfconv' if env['BF_BUILDINFO']: defs.append('WITH_BUILDINFO') +if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'win64-vc', 'win64-mingw'): + if env['WITH_BF_IME']: + defs.append('WITH_INPUT_IME') + if env['WITH_BF_INTERNATIONAL']: defs.append('WITH_INTERNATIONAL') diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index e1cd334637a..d2abfd419d1 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -47,6 +47,7 @@ extern "C" { #endif struct bContext; +struct GHashIterator; struct IDProperty; struct wmEvent; struct wmEventHandler; @@ -223,12 +224,13 @@ void WM_operator_stack_clear(struct wmWindowManager *wm); void WM_operator_handlers_clear(wmWindowManager *wm, struct wmOperatorType *ot); struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet); -struct GHashIterator *WM_operatortype_iter(void); +void WM_operatortype_iter(struct GHashIterator *ghi); void WM_operatortype_append(void (*opfunc)(struct wmOperatorType *)); void WM_operatortype_append_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata); void WM_operatortype_append_macro_ptr(void (*opfunc)(struct wmOperatorType *, void *), void *userdata); void WM_operatortype_remove_ptr(struct wmOperatorType *ot); bool WM_operatortype_remove(const char *idname); +void WM_operatortype_last_properties_clear_all(void); struct wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag); struct wmOperatorTypeMacro *WM_operatortype_macro_define(struct wmOperatorType *ot, const char *idname); @@ -266,6 +268,7 @@ void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int bool WM_operator_check_ui_enabled(const struct bContext *C, const char *idname); wmOperator *WM_operator_last_redo(const struct bContext *C); +ID *WM_operator_drop_load_path(struct bContext *C, struct wmOperator *op, const short idcode); bool WM_operator_last_properties_init(struct wmOperator *op); bool WM_operator_last_properties_store(struct wmOperator *op); @@ -395,6 +398,7 @@ enum { WM_JOB_TYPE_CLIP_SOLVE_CAMERA, WM_JOB_TYPE_CLIP_PREFETCH, WM_JOB_TYPE_SEQ_BUILD_PROXY, + WM_JOB_TYPE_SEQ_BUILD_PREVIEW, /* add as needed, screencast, seq proxy build * if having hard coded values is a problem */ }; @@ -458,6 +462,10 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4 float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]); bool WM_event_is_tablet(const struct wmEvent *event); +#ifdef WITH_INPUT_IME +bool WM_event_is_ime_switch(const struct wmEvent *event); +#endif + #ifdef __cplusplus } #endif diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index ff252f0fc20..0e3e65d2e21 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -94,12 +94,12 @@ * </pre> * * A common way to get the space from the ScrArea: - * <pre> - * if (sa->spacetype == SPACE_VIEW3D) { - * View3D *v3d = sa->spacedata.first; - * ... - * } - * </pre> + * \code{.c} + * if (sa->spacetype == SPACE_VIEW3D) { + * View3D *v3d = sa->spacedata.first; + * ... + * } + * \endcode */ #ifdef __cplusplus @@ -169,7 +169,7 @@ enum { #define KM_OSKEY2 128 /* KM_MOD_ flags for wmKeyMapItem and wmEvent.alt/shift/oskey/ctrl */ -/* note that KM_ANY and false are used with these defines too */ +/* note that KM_ANY and KM_NOTHING are used with these defines too */ #define KM_MOD_FIRST 1 #define KM_MOD_SECOND 2 @@ -239,6 +239,7 @@ typedef struct wmNotifier { #define NC_MASK (21<<24) #define NC_GPENCIL (22<<24) #define NC_LINESTYLE (23<<24) +#define NC_CAMERA (24<<24) /* data type, 256 entries is enough, it can overlap */ #define NOTE_DATA 0x00FF0000 @@ -297,6 +298,7 @@ typedef struct wmNotifier { #define ND_POINTCACHE (28<<16) #define ND_PARENT (29<<16) #define ND_LOD (30<<16) +#define ND_DRAW_RENDER_VIEWPORT (31<<16) /* for camera & sequencer viewport update, also /w NC_SCENE */ /* NC_MATERIAL Material */ #define ND_SHADING (30<<16) @@ -324,6 +326,9 @@ typedef struct wmNotifier { #define ND_NLA_ACTCHANGE (74<<16) #define ND_FCURVES_ORDER (75<<16) + /* NC_GPENCIL */ +#define ND_GPENCIL_EDITMODE (85<<16) + /* NC_GEOM Geometry */ /* Mesh, Curve, MetaBall, Armature, .. */ #define ND_SELECT (90<<16) @@ -554,9 +559,7 @@ typedef struct wmOperatorType { /* pointer to modal keymap, do not free! */ struct wmKeyMap *modalkeymap; - /* only used for operators defined with python - * use to store pointers to python functions */ - void *pyop_data; + /* python needs the operator type as well */ int (*pyop_poll)(struct bContext *, struct wmOperatorType *ot) ATTR_WARN_UNUSED_RESULT; /* RNA integration */ @@ -567,6 +570,24 @@ typedef struct wmOperatorType { } wmOperatorType; +#ifdef WITH_INPUT_IME +/* *********** Input Method Editor (IME) *********** */ + +/* similar to GHOST_TEventImeData */ +typedef struct wmIMEData { + size_t result_len, composite_len; + + char *str_result; /* utf8 encoding */ + char *str_composite; /* utf8 encoding */ + + int cursor_pos; /* cursor position in the IME composition. */ + int sel_start; /* beginning of the selection */ + int sel_end; /* end of the selection */ + + bool is_ime_composing; +} wmIMEData; +#endif + /* **************** Paint Cursor ******************* */ typedef void (*wmPaintCursorDraw)(struct bContext *C, int, int, void *customdata); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index d05cc572c45..34069e0b873 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -39,8 +39,6 @@ #include "DNA_windowmanager_types.h" -#include "GHOST_C-api.h" - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -59,7 +57,6 @@ #include "WM_types.h" #include "wm_window.h" #include "wm_event_system.h" -#include "wm_event_types.h" #include "wm_draw.h" #include "wm.h" @@ -155,7 +152,7 @@ void wm_operator_register(bContext *C, wmOperator *op) int tot; BLI_addtail(&wm->operators, op); - tot = BLI_countlist(&wm->operators); + tot = BLI_listbase_count(&wm->operators); while (tot > MAX_OP_REGISTERED) { wmOperator *opt = wm->operators.first; @@ -253,15 +250,14 @@ void WM_uilisttype_init(void) void WM_uilisttype_free(void) { - GHashIterator *iter = BLI_ghashIterator_new(uilisttypes_hash); + GHashIterator gh_iter; - for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) { - uiListType *ult = BLI_ghashIterator_getValue(iter); + GHASH_ITER (gh_iter, uilisttypes_hash) { + uiListType *ult = BLI_ghashIterator_getValue(&gh_iter); if (ult->ext.free) { ult->ext.free(ult->ext.data); } } - BLI_ghashIterator_free(iter); BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN); uilisttypes_hash = NULL; @@ -312,15 +308,14 @@ void WM_menutype_init(void) void WM_menutype_free(void) { - GHashIterator *iter = BLI_ghashIterator_new(menutypes_hash); + GHashIterator gh_iter; - for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) { - MenuType *mt = BLI_ghashIterator_getValue(iter); + GHASH_ITER (gh_iter, menutypes_hash) { + MenuType *mt = BLI_ghashIterator_getValue(&gh_iter); if (mt->ext.free) { mt->ext.free(mt->ext.data); } } - BLI_ghashIterator_free(iter); BLI_ghash_free(menutypes_hash, NULL, MEM_freeN); menutypes_hash = NULL; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index e5bba9285b4..cdc3c9eaaff 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -45,10 +45,8 @@ #include "BIF_glutil.h" #include "BKE_context.h" -#include "BKE_screen.h" #include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" #include "UI_interface.h" #include "UI_interface_icons.h" @@ -58,8 +56,6 @@ #include "WM_api.h" #include "WM_types.h" #include "wm_event_system.h" -#include "wm.h" - /* ****************************************************** */ @@ -85,7 +81,7 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid) for (dm = dropboxes.first; dm; dm = dm->next) if (dm->spaceid == spaceid && dm->regionid == regionid) - if (0 == strncmp(idname, dm->idname, KMAP_MAX_NAME)) + if (STREQLEN(idname, dm->idname, KMAP_MAX_NAME)) return &dm->dropboxes; dm = MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list"); @@ -271,16 +267,11 @@ void wm_drags_check_ops(bContext *C, wmEvent *event) static void wm_drop_operator_draw(const char *name, int x, int y) { - int width = UI_GetStringWidth(name); - int padding = 4 * UI_DPI_FAC; - - glColor4ub(0, 0, 0, 50); - - uiSetRoundBox(UI_CNR_ALL | UI_RB_ALPHA); - uiRoundBox(x, y, x + width + 2 * padding, y + 4 * padding, padding); - - glColor4ub(255, 255, 255, 255); - UI_DrawString(x + padding, y + padding, name); + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + const unsigned char fg[4] = {255, 255, 255, 255}; + const unsigned char bg[4] = {0, 0, 0, 50}; + + UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg); } static const char *wm_drag_name(wmDrag *drag) @@ -288,13 +279,12 @@ static const char *wm_drag_name(wmDrag *drag) switch (drag->type) { case WM_DRAG_ID: { - ID *id = (ID *)drag->poin; + ID *id = drag->poin; return id->name + 2; } case WM_DRAG_PATH: - return drag->path; case WM_DRAG_NAME: - return (char *)drag->path; + return drag->path; } return ""; } @@ -315,6 +305,7 @@ static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2) /* if rect set, do not draw */ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) { + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; wmWindowManager *wm = CTX_wm_manager(C); wmDrag *drag; const int winsize_y = WM_window_pixels_y(win); @@ -330,7 +321,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) /* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */ glEnable(GL_BLEND); for (drag = wm->drags.first; drag; drag = drag->next) { - int iconsize = 16 * UI_DPI_FAC; /* assumed to be 16 pixels */ + int iconsize = UI_DPI_ICON_SIZE; int padding = 4 * UI_DPI_FAC; /* image or icon */ @@ -366,12 +357,12 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) } if (rect) { - int w = UI_GetStringWidth(wm_drag_name(drag)); + int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag)); drag_rect_minmax(rect, x, y, x + w, y + iconsize); } else { glColor4ub(255, 255, 255, 255); - UI_DrawString(x, y, wm_drag_name(drag)); + UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag)); } /* operator name with roundbox */ @@ -387,14 +378,16 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect) else { x = cursorx - 2 * padding; - if (cursory + iconsize + iconsize < winsize_y) - y = cursory + iconsize; - else - y = cursory - iconsize - 2 * UI_DPI_FAC; + if (cursory + iconsize + iconsize < winsize_y) { + y = (cursory + iconsize) + padding; + } + else { + y = (cursory - iconsize) - padding; + } } if (rect) { - int w = UI_GetStringWidth(wm_drag_name(drag)); + int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag)); drag_rect_minmax(rect, x, y, x + w, y + iconsize); } else diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 793908ec44b..f1a46826435 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -71,6 +71,8 @@ #include "BIF_gl.h" +#include "GPU_debug.h" + #include "UI_interface.h" #include "PIL_time.h" @@ -81,7 +83,6 @@ #include "wm_window.h" #include "wm_event_system.h" #include "wm_event_types.h" -#include "wm_draw.h" #ifndef NDEBUG # include "RNA_enum_types.h" @@ -269,7 +270,7 @@ void wm_event_do_notifiers(bContext *C) if (note->category == NC_SCREEN) { if (note->data == ND_SCREENBROWSE) { /* free popup handlers only [#35434] */ - UI_remove_popup_handlers_all(C, &win->modalhandlers); + UI_popup_handlers_remove_all(C, &win->modalhandlers); ED_screen_set(C, note->reference); // XXX hrms, think this over! @@ -542,7 +543,7 @@ void WM_event_print(const wmEvent *event) event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier, event->x, event->y, event->ascii, BLI_str_utf8_size(event->utf8_buf), event->utf8_buf, - event->keymap_idname, (void *)event); + event->keymap_idname, (const void *)event); if (ISNDOF(event->type)) { const wmNDOFMotionData *ndof = event->customdata; @@ -621,7 +622,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca { if (caller_owns_reports == false) { /* popup */ if (op->reports->list.first) { - /* FIXME, temp setting window, see other call to uiPupMenuReports for why */ + /* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */ wmWindow *win_prev = CTX_wm_window(C); ScrArea *area_prev = CTX_wm_area(C); ARegion *ar_prev = CTX_wm_region(C); @@ -629,7 +630,7 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca if (win_prev == NULL) CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); - uiPupMenuReports(C, op->reports); + UI_popup_menu_reports(C, op->reports); CTX_wm_window_set(C, win_prev); CTX_wm_area_set(C, area_prev); @@ -730,7 +731,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons /* XXX Disabled the repeat check to address part 2 of #31840. * Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason * why this was needed, but worth to note it in case something turns bad. (mont29) */ - if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)/* && repeat == 0 */) + if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */) wm_operator_reports(C, op, retval, false); if (retval & OPERATOR_FINISHED) { @@ -871,7 +872,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, break; /* skip invalid properties */ - if (strcmp(RNA_property_identifier(prop), otmacro->idname) == 0) { + if (STREQ(RNA_property_identifier(prop), otmacro->idname)) { wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0); PointerRNA someptr = RNA_property_pointer_get(properties, prop); wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL); @@ -1663,7 +1664,6 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand int action = WM_HANDLER_CONTINUE; switch (val) { - case EVT_FILESELECT_OPEN: case EVT_FILESELECT_FULL_OPEN: { ScrArea *sa; @@ -1677,9 +1677,16 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand else { sa = handler->op_area; } - - if (val == EVT_FILESELECT_OPEN) { + + if (sa->full) { + /* ensure the first area becomes the file browser, because the second one is the small + * top (info-)area which might be too small (in fullscreens we have max two areas) */ + if (sa->prev) { + sa = sa->prev; + } ED_area_newspace(C, sa, SPACE_FILE); /* 'sa' is modified in-place */ + /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ + sa->flag |= AREA_FLAG_STACKED_FULLSCREEN; } else { sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */ @@ -1703,24 +1710,16 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand case EVT_FILESELECT_CANCEL: case EVT_FILESELECT_EXTERNAL_CANCEL: { - /* XXX validate area and region? */ - bScreen *screen = CTX_wm_screen(C); - /* remlink now, for load file case before removing*/ BLI_remlink(handlers, handler); - + if (val != EVT_FILESELECT_EXTERNAL_CANCEL) { - if (screen != handler->filescreen) { - ED_screen_full_prevspace(C, CTX_wm_area(C)); - } - else { - ED_area_prevspace(C, CTX_wm_area(C)); - } + ED_screen_full_prevspace(C, CTX_wm_area(C)); } - + wm_handler_op_context(C, handler); - /* needed for uiPupMenuReports */ + /* needed for UI_popup_menu_reports */ if (val == EVT_FILESELECT_EXEC) { int retval; @@ -1752,7 +1751,7 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first); BKE_report_print_level_set(handler->op->reports, RPT_WARNING); - uiPupMenuReports(C, handler->op->reports); + UI_popup_menu_reports(C, handler->op->reports); /* XXX - copied from 'wm_operator_finished()' */ /* add reports to the global list, otherwise they are not seen */ @@ -1955,7 +1954,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers event->customdata = NULL; event->custom = 0; - WM_operator_name_call(C, drop->ot->idname, drop->opcontext, drop->ptr); + WM_operator_name_call_ptr(C, drop->ot, drop->opcontext, drop->ptr); action |= WM_HANDLER_BREAK; /* XXX fileread case */ @@ -2323,6 +2322,14 @@ void wm_event_do_handlers(bContext *C) } for (sa = win->screen->areabase.first; sa; sa = sa->next) { + /* after restoring a screen from SCREENMAXIMIZED we have to wait + * with the screen handling till the region coordinates are updated */ + if (win->screen->skip_handling == true) { + /* restore for the next iteration of wm_event_do_handlers */ + win->screen->skip_handling = false; + break; + } + if (wm_event_inside_i(event, &sa->totrct)) { CTX_wm_area_set(C, sa); @@ -2417,12 +2424,7 @@ void wm_event_do_handlers(bContext *C) /* update key configuration after handling events */ WM_keyconfig_update(wm); - if (G.debug) { - GLenum error = glGetError(); - if (error != GL_NO_ERROR) { - printf("GL error: %s\n", gluErrorString(error)); - } - } + GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers"); } /* ********** filesector handling ************ */ @@ -2456,7 +2458,6 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) wmEventHandler *handler, *handlernext; wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - int full = 1; // XXX preset? /* only allow 1 file selector open per window */ for (handler = win->modalhandlers.first; handler; handler = handlernext) { @@ -2491,7 +2492,6 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) handler->op = op; handler->op_area = CTX_wm_area(C); handler->op_region = CTX_wm_region(C); - handler->filescreen = CTX_wm_screen(C); BLI_addhead(&win->modalhandlers, handler); @@ -2501,7 +2501,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) op->type->check(C, op); /* ignore return value */ } - WM_event_fileselect_event(wm, op, full ? EVT_FILESELECT_FULL_OPEN : EVT_FILESELECT_OPEN); + WM_event_fileselect_event(wm, op, EVT_FILESELECT_FULL_OPEN); } #if 0 @@ -3050,6 +3050,13 @@ static void wm_event_add_mousemove(wmWindow *win, const wmEvent *event) void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int UNUSED(time), void *customdata) { wmWindow *owin; + + /* Having both, event and evt, can be highly confusing to work with, but is necessary for + * our current event system, so let's clear things up a bit: + * - data added to event only will be handled immediately, but will not be copied to the next event + * - data added to evt only stays, but is handled with the next event -> execution delay + * - data added to event and evt stays and is handled immediately + */ wmEvent event, *evt = win->eventstate; /* initialize and copy state (only mouse x y and modifiers) */ @@ -3190,6 +3197,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U case GHOST_kEventKeyUp: { GHOST_TEventKeyData *kd = customdata; + short keymodifier = KM_NOTHING; event.type = convert_key(kd->key); event.ascii = kd->ascii; memcpy(event.utf8_buf, kd->utf8_buf, sizeof(event.utf8_buf)); /* might be not null terminated*/ @@ -3230,28 +3238,38 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U } } - /* modifiers assign to eventstate, so next event gets the modifer (makes modifier key events work) */ /* assigning both first and second is strange - campbell */ switch (event.type) { - case LEFTSHIFTKEY: case RIGHTSHIFTKEY: - evt->shift = (event.val == KM_PRESS) ? - ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + if (event.val == KM_PRESS) { + if (evt->ctrl || evt->alt || evt->oskey) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.shift = evt->shift = keymodifier; break; - case LEFTCTRLKEY: case RIGHTCTRLKEY: - evt->ctrl = (event.val == KM_PRESS) ? - ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + case LEFTCTRLKEY: + case RIGHTCTRLKEY: + if (event.val == KM_PRESS) { + if (evt->shift || evt->alt || evt->oskey) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.ctrl = evt->ctrl = keymodifier; break; - case LEFTALTKEY: case RIGHTALTKEY: - evt->alt = (event.val == KM_PRESS) ? - ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + case LEFTALTKEY: + case RIGHTALTKEY: + if (event.val == KM_PRESS) { + if (evt->ctrl || evt->shift || evt->oskey) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.alt = evt->alt = keymodifier; break; case OSKEY: - evt->oskey = (event.val == KM_PRESS) ? - ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : - false; + if (event.val == KM_PRESS) { + if (evt->ctrl || evt->alt || evt->shift) keymodifier = (KM_MOD_FIRST | KM_MOD_SECOND); + else keymodifier = KM_MOD_FIRST; + } + event.oskey = evt->oskey = keymodifier; break; default: if (event.val == KM_PRESS && event.keymodifier == 0) @@ -3374,6 +3392,35 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U break; } +#ifdef WITH_INPUT_IME + case GHOST_kEventImeCompositionStart: + { + event.val = KM_PRESS; + win->ime_data = customdata; + win->ime_data->is_ime_composing = true; + event.type = WM_IME_COMPOSITE_START; + wm_event_add(win, &event); + break; + } + case GHOST_kEventImeComposition: + { + event.val = KM_PRESS; + event.type = WM_IME_COMPOSITE_EVENT; + wm_event_add(win, &event); + break; + } + case GHOST_kEventImeCompositionEnd: + { + event.val = KM_PRESS; + if (win->ime_data) { + win->ime_data->is_ime_composing = false; + } + event.type = WM_IME_COMPOSITE_END; + wm_event_add(win, &event); + break; + } +#endif /* WITH_INPUT_IME */ + } #if 0 @@ -3480,5 +3527,13 @@ bool WM_event_is_tablet(const struct wmEvent *event) return (event->tablet_data) ? true : false; } +#ifdef WITH_INPUT_IME +/* most os using ctrl/oskey + space to switch ime, avoid added space */ +bool WM_event_is_ime_switch(const struct wmEvent *event) +{ + return event->val == KM_PRESS && event->type == SPACEKEY && + (event->ctrl || event->oskey || event->shift || event->alt); +} +#endif /** \} */ diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 7865e09cbe2..f5a7ad164d6 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -69,6 +69,7 @@ #include "DNA_screen_types.h" #include "DNA_windowmanager_types.h" +#include "BKE_appdir.h" #include "BKE_utildefines.h" #include "BKE_autoexec.h" #include "BKE_blender.h" @@ -96,8 +97,6 @@ #include "ED_view3d.h" #include "ED_util.h" -#include "RE_pipeline.h" /* only to report missing engine */ - #include "GHOST_C-api.h" #include "GHOST_Path-api.h" @@ -319,7 +318,7 @@ static void wm_init_userdef(bContext *C, const bool from_memory) } /* update tempdir from user preferences */ - BLI_temp_dir_init(U.tempdir); + BKE_tempdir_init(U.tempdir); BKE_userdef_state(); } @@ -356,7 +355,7 @@ static int wm_read_exotic(Scene *UNUSED(scene), const char *name) else { len = gzread(gzfile, header, sizeof(header)); gzclose(gzfile); - if (len == sizeof(header) && strncmp(header, "BLENDER", 7) == 0) { + if (len == sizeof(header) && STREQLEN(header, "BLENDER", 7)) { retval = BKE_READ_EXOTIC_OK_BLEND; } else { @@ -476,6 +475,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) BPY_python_reset(C); #endif + WM_operatortype_last_properties_clear_all(); + /* important to do before NULL'ing the context */ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); @@ -534,11 +535,13 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) } -/* called on startup, (context entirely filled with NULLs) */ -/* or called for 'New File' */ -/* both startup.blend and userpref.blend are checked */ -/* the optional paramater custom_file points to an alterntive startup page */ -/* custom_file can be NULL */ +/** + * called on startup, (context entirely filled with NULLs) + * or called for 'New File' + * both startup.blend and userpref.blend are checked + * the optional parameter custom_file points to an alternative startup page + * custom_file can be NULL + */ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file) { ListBase wmbase; @@ -560,13 +563,17 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c /* options exclude eachother */ BLI_assert((from_memory && custom_file) == 0); + if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) { + BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC); + } + BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE); UI_view2d_zoom_cache_reset(); G.relbase_valid = 0; if (!from_memory) { - const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); + const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); if (custom_file) { BLI_strncpy(startstr, custom_file, FILE_MAX); @@ -612,7 +619,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c if (BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); } - BLI_temp_dir_init(U.tempdir); + BKE_tempdir_init(U.tempdir); #ifdef WITH_PYTHON_SECURITY /* use alternative setting for security nuts @@ -668,6 +675,8 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c } #endif + WM_operatortype_last_properties_clear_all(); + /* important to do before NULL'ing the context */ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); @@ -723,7 +732,7 @@ void wm_read_history(void) struct RecentFile *recent; const char *line; int num; - const char * const cfgdir = BLI_get_folder(BLENDER_USER_CONFIG, NULL); + const char * const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); if (!cfgdir) return; @@ -760,7 +769,7 @@ static void write_history(void) return; /* will be NULL in background mode */ - user_config_dir = BLI_get_folder_create(BLENDER_USER_CONFIG, NULL); + user_config_dir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL); if (!user_config_dir) return; @@ -837,11 +846,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt) if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, OB_SOLID, false, false, R_ADDSKY, err_out); + IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, err_out); } else { ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2, - IB_rect, false, R_ADDSKY, err_out); + IB_rect, false, R_ALPHAPREMUL, err_out); } if (ibuf) { @@ -1011,6 +1020,8 @@ int wm_homefile_write_exec(bContext *C, wmOperator *op) char filepath[FILE_MAX]; int fileflags; + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE); + /* check current window and close it if temp */ if (win && win->screen->temp) wm_window_close(C, wm, win); @@ -1018,7 +1029,7 @@ int wm_homefile_write_exec(bContext *C, wmOperator *op) /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE); + BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_STARTUP_FILE); printf("trying to save homefile at %s ", filepath); ED_editors_flush_edits(C, false); @@ -1035,6 +1046,8 @@ int wm_homefile_write_exec(bContext *C, wmOperator *op) G.save_over = 0; + BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_POST); + return OPERATOR_FINISHED; } @@ -1047,7 +1060,7 @@ int wm_userpref_write_exec(bContext *C, wmOperator *op) /* update keymaps in user preferences */ WM_keyconfig_update(wm); - BLI_make_file_string("/", filepath, BLI_get_folder_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE); + BLI_make_file_string("/", filepath, BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL), BLENDER_USERPREF_FILE); printf("trying to save userpref at %s ", filepath); if (BKE_write_file_userdef(filepath, op->reports) == 0) { @@ -1064,12 +1077,20 @@ int wm_userpref_write_exec(bContext *C, wmOperator *op) void wm_autosave_location(char *filepath) { - char pidstr[32]; + const int pid = abs(getpid()); + char path[1024]; #ifdef WIN32 const char *savedir; #endif - BLI_snprintf(pidstr, sizeof(pidstr), "%d.blend", abs(getpid())); + if (G.main && G.relbase_valid) { + const char *basename = BLI_path_basename(G.main->name); + int len = strlen(basename) - 6; + BLI_snprintf(path, sizeof(path), "%.*s-%d.blend", len, basename, pid); + } + else { + BLI_snprintf(path, sizeof(path), "%d.blend", pid); + } #ifdef WIN32 /* XXX Need to investigate how to handle default location of '/tmp/' @@ -1080,14 +1101,14 @@ void wm_autosave_location(char *filepath) * BLI_make_file_string will create string that has it most likely on C:\ * through get_default_root(). * If there is no C:\tmp autosave fails. */ - if (!BLI_exists(BLI_temp_dir_base())) { - savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL); - BLI_make_file_string("/", filepath, savedir, pidstr); + if (!BLI_exists(BKE_tempdir_base())) { + savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, NULL); + BLI_make_file_string("/", filepath, savedir, path); return; } #endif - BLI_make_file_string("/", filepath, BLI_temp_dir_base(), pidstr); + BLI_make_file_string("/", filepath, BKE_tempdir_base(), path); } void WM_autosave_init(wmWindowManager *wm) @@ -1151,7 +1172,7 @@ void wm_autosave_delete(void) if (BLI_exists(filename)) { char str[FILE_MAX]; - BLI_make_file_string("/", str, BLI_temp_dir_base(), BLENDER_QUIT_FILE); + BLI_make_file_string("/", str, BKE_tempdir_base(), BLENDER_QUIT_FILE); /* if global undo; remove tempsave, otherwise rename */ if (U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, false, false); diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 3e287a3907b..46c3909f7bf 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -49,7 +49,6 @@ #include "WM_types.h" #include "wm.h" -#include "wm_event_system.h" #include "wm_subwindow.h" #include "wm_draw.h" diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index f762e19c969..9778f1651de 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -40,9 +40,6 @@ #include "MEM_guardedalloc.h" -#include "IMB_imbuf_types.h" -#include "IMB_imbuf.h" - #include "DNA_scene_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" @@ -68,6 +65,7 @@ #include "BKE_report.h" #include "BKE_addon.h" +#include "BKE_appdir.h" #include "BKE_sequencer.h" /* free seq clipboard */ #include "BKE_material.h" /* clear_matcopybuf */ #include "BKE_tracking.h" /* free tracking clipboard */ @@ -98,6 +96,7 @@ #include "wm_window.h" #include "ED_armature.h" +#include "ED_gpencil.h" #include "ED_keyframing.h" #include "ED_node.h" #include "ED_render.h" @@ -110,7 +109,6 @@ #include "BLF_translation.h" #include "GPU_buffers.h" -#include "GPU_extensions.h" #include "GPU_draw.h" #include "GPU_init_exit.h" @@ -172,6 +170,8 @@ void WM_init(bContext *C, int argc, const char **argv) BLF_lang_set(NULL); + ED_spacemacros_init(); + /* note: there is a bug where python needs initializing before loading the * startup.blend because it may contain PyDrivers. It also needs to be after * initializing space types and other internal data. @@ -190,8 +190,6 @@ void WM_init(bContext *C, int argc, const char **argv) (void)argv; /* unused */ #endif - ED_spacemacros_init(); - if (!G.background && !wm_start_with_console) GHOST_toggleConsole(3); @@ -219,7 +217,7 @@ void WM_init(bContext *C, int argc, const char **argv) /* allow a path of "", this is what happens when making a new file */ #if 0 if (G.main->name[0] == 0) - BLI_make_file_string("/", G.main->name, BLI_getDefaultDocumentFolder(), "untitled.blend"); + BLI_make_file_string("/", G.main->name, BKE_appdir_folder_default(), "untitled.blend"); #endif BLI_strncpy(G.lib, G.main->name, FILE_MAX); @@ -414,7 +412,7 @@ void WM_exit_ext(bContext *C, const bool do_python) bool has_edited; int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY); - BLI_make_file_string("/", filename, BLI_temp_dir_base(), BLENDER_QUIT_FILE); + BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE); has_edited = ED_editors_flush_edits(C, false); @@ -478,6 +476,7 @@ void WM_exit_ext(bContext *C, const bool do_python) free_anim_copybuf(); free_anim_drivers_copybuf(); free_fmodifiers_copybuf(); + ED_gpencil_strokes_copybuf_free(); ED_clipboard_posebuf_free(); BKE_node_clipboard_clear(); @@ -538,12 +537,15 @@ void WM_exit_ext(bContext *C, const bool do_python) BLI_threadapi_exit(); if (MEM_get_memory_blocks_in_use() != 0) { - printf("Error: Not freed memory blocks: %d\n", MEM_get_memory_blocks_in_use()); + size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); + printf("Error: Not freed memory blocks: %d, total unfreed memory %f MB\n", + MEM_get_memory_blocks_in_use(), + (double)mem_in_use / 1024 / 1024); MEM_printmemlist(); } wm_autosave_delete(); - BLI_temp_dir_session_purge(); + BKE_tempdir_session_purge(); } void WM_exit(bContext *C) diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 74c504050ae..6bc858e861a 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -45,8 +45,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm_window.h" -#include "wm_event_system.h" #include "wm_event_types.h" #include "wm.h" @@ -630,17 +628,22 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) } } - /* on file load 'winactive' can be NULL, possibly it should not happen but for now do a NULL check - campbell */ - if (wm->winactive) { - /* if there are running jobs, set the global progress indicator */ - if (jobs_progress > 0) { - float progress = total_progress / (float)jobs_progress; - WM_progress_set(wm->winactive, progress); - } - else { - WM_progress_clear(wm->winactive); - } + + /* if there are running jobs, set the global progress indicator */ + if (jobs_progress > 0) { + wmWindow *win; + float progress = total_progress / (float)jobs_progress; + + for (win = wm->windows.first; win; win = win->next) + WM_progress_set(win, progress); } + else { + wmWindow *win; + + for (win = wm->windows.first; win; win = win->next) + WM_progress_clear(win); + } + } bool WM_jobs_has_running(wmWindowManager *wm) diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index ff90de4b3c6..82e46c1b333 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -56,7 +56,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "wm_window.h" #include "wm_event_system.h" #include "wm_event_types.h" @@ -146,21 +145,15 @@ static void wm_keyconfig_properties_update_ot(ListBase *km_lb) } } -static int wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b) +static bool wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b) { - if (strcmp(a->idname, b->idname) != 0) - return 0; - - if (!RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE)) - return 0; - - if ((a->flag & KMI_INACTIVE) != (b->flag & KMI_INACTIVE)) - return 0; - - return (a->propvalue == b->propvalue); + return (STREQ(a->idname, b->idname) && + RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) && + (a->flag & KMI_INACTIVE) == (b->flag & KMI_INACTIVE) && + a->propvalue == b->propvalue); } -static int wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b) +static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b) { return (wm_keymap_item_equals_result(a, b) && a->type == b->type && @@ -267,7 +260,7 @@ wmKeyConfig *WM_keyconfig_new_user(wmWindowManager *wm, const char *idname) bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf) { if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) { - if (strncmp(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr)) == 0) { + if (STREQLEN(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr))) { BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr)); WM_keyconfig_update_tag(NULL, NULL); } @@ -422,7 +415,7 @@ wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int ty wmKeyMapItem *kmi; for (kmi = keymap->items.first; kmi; kmi = kmi->next) - if (strncmp(kmi->idname, idname, OP_MAX_TYPENAME) == 0) + if (STREQLEN(kmi->idname, idname, OP_MAX_TYPENAME)) break; if (kmi == NULL) { kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); @@ -729,7 +722,7 @@ wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int for (km = lb->first; km; km = km->next) if (km->spaceid == spaceid && km->regionid == regionid) - if (0 == strncmp(idname, km->idname, KMAP_MAX_NAME)) + if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) return km; return NULL; @@ -788,7 +781,7 @@ wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname) for (km = keyconf->keymaps.first; km; km = km->next) if (km->flag & KEYMAP_MODAL) - if (0 == strncmp(idname, km->idname, KMAP_MAX_NAME)) + if (STREQLEN(idname, km->idname, KMAP_MAX_NAME)) break; return km; @@ -953,18 +946,17 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( if (kmi->flag & KMI_INACTIVE) continue; - if (strcmp(kmi->idname, opname) == 0 && WM_key_event_string(kmi->type)[0]) { + if (STREQ(kmi->idname, opname) && WM_key_event_string(kmi->type)[0]) { if (is_hotkey) { if (!ISHOTKEY(kmi->type)) continue; } if (properties) { - /* example of debugging keymaps */ #if 0 if (kmi->ptr) { - if (strcmp("MESH_OT_rip_move", opname) == 0) { + if (STREQ("MESH_OT_rip_move", opname)) { printf("OPERATOR\n"); IDP_spit(properties); printf("KEYMAP\n"); @@ -977,6 +969,39 @@ static wmKeyMapItem *wm_keymap_item_find_handlers( if (keymap_r) *keymap_r = keymap; return kmi; } + /* Debug only, helps spotting mismatches between menu entries and shortcuts! */ + else if (G.debug & G_DEBUG_WM) { + if (is_strict && kmi->ptr) { + wmOperatorType *ot = WM_operatortype_find(opname, true); + if (ot) { + /* make a copy of the properties and set unset ones to their default values. */ + PointerRNA opptr; + IDProperty *properties_default = IDP_CopyProperty(kmi->ptr->data); + + RNA_pointer_create(NULL, ot->srna, properties_default, &opptr); + WM_operator_properties_default(&opptr, true); + + if (IDP_EqualsProperties_ex(properties, properties_default, is_strict)) { + char kmi_str[128]; + WM_keymap_item_to_string(kmi, kmi_str, sizeof(kmi_str)); + /* Note gievn properties could come from other things than menu entry... */ + printf("%s: Some set values in menu entry match default op values, " + "this might not be desired!\n", opname); + printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str); +#ifndef NDEBUG + printf("OPERATOR\n"); + IDP_spit(properties); + printf("KEYMAP\n"); + IDP_spit(kmi->ptr->data); +#endif + printf("\n"); + } + + IDP_FreeProperty(properties_default); + MEM_freeN(properties_default); + } + } + } } else { if (keymap_r) *keymap_r = keymap; @@ -1043,33 +1068,83 @@ static wmKeyMapItem *wm_keymap_item_find_props( static wmKeyMapItem *wm_keymap_item_find( const bContext *C, const char *opname, int opcontext, - IDProperty *properties, const bool is_hotkey, const bool is_strict, wmKeyMap **keymap_r) + IDProperty *properties, const bool is_hotkey, bool is_strict, wmKeyMap **keymap_r) { - wmKeyMapItem *found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + wmKeyMapItem *found; + /* XXX Hack! Macro operators in menu entry have their whole props defined, which is not the case for + * relevant keymap entries. Could be good to check and harmonize this, but for now always + * compare non-strict in this case. + */ + wmOperatorType *ot = WM_operatortype_find(opname, true); + if (ot) { + is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0); + } + + found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r); + + /* This block is *only* useful in one case: when op uses an enum menu in its prop member + * (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle, + * since now any enum prop may be used in UI (specified by name), ot->prop is not so much used... + * Otherwise: + * * If non-strict, unset properties always match set ones in IDP_EqualsProperties_ex. + * * If strict, unset properties never match set ones in IDP_EqualsProperties_ex, + * and we do not want that to change (else we get things like T41757)! + * ...so in either case, re-running a comparison with unset props set to default is useless. + */ if (!found && properties) { - wmOperatorType *ot = WM_operatortype_find(opname, true); - if (ot) { - /* make a copy of the properties and set any unset props - * to their default values, so the ID property compare function succeeds */ + if (ot && ot->prop) { /* XXX Shall we also check ot->prop is actually an enum? */ + /* make a copy of the properties and unset the 'ot->prop' one if set. */ PointerRNA opptr; - IDProperty *properties_default = IDP_CopyProperty(properties); + IDProperty *properties_temp = IDP_CopyProperty(properties); - RNA_pointer_create(NULL, ot->srna, properties_default, &opptr); + RNA_pointer_create(NULL, ot->srna, properties_temp, &opptr); - if (WM_operator_properties_default(&opptr, true) || - (!is_strict && ot->prop && RNA_property_is_set(&opptr, ot->prop))) - { - /* for operator that has enum menu, unset it so it always matches */ - if (!is_strict && ot->prop) { - RNA_property_unset(&opptr, ot->prop); - } + if (RNA_property_is_set(&opptr, ot->prop)) { + /* for operator that has enum menu, unset it so its value does not affect comparison result */ + RNA_property_unset(&opptr, ot->prop); - found = wm_keymap_item_find_props(C, opname, opcontext, properties_default, false, is_hotkey, keymap_r); + found = wm_keymap_item_find_props(C, opname, opcontext, properties_temp, + is_strict, is_hotkey, keymap_r); } - IDP_FreeProperty(properties_default); - MEM_freeN(properties_default); + IDP_FreeProperty(properties_temp); + MEM_freeN(properties_temp); + } + } + + /* Debug only, helps spotting mismatches between menu entries and shortcuts! */ + if (G.debug & G_DEBUG_WM) { + if (!found && is_strict && properties) { + wmKeyMap *km; + wmKeyMapItem *kmi; + if (ot) { + /* make a copy of the properties and set unset ones to their default values. */ + PointerRNA opptr; + IDProperty *properties_default = IDP_CopyProperty(properties); + + RNA_pointer_create(NULL, ot->srna, properties_default, &opptr); + WM_operator_properties_default(&opptr, true); + + kmi = wm_keymap_item_find_props(C, opname, opcontext, properties_default, is_strict, is_hotkey, &km); + if (kmi) { + char kmi_str[128]; + WM_keymap_item_to_string(kmi, kmi_str, sizeof(kmi_str)); + printf("%s: Some set values in keymap entry match default op values, " + "this might not be desired!\n", opname); + printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str); +#ifndef NDEBUG + printf("OPERATOR\n"); + IDP_spit(properties); + printf("KEYMAP\n"); + IDP_spit(kmi->ptr->data); +#endif + printf("\n"); + } + + IDP_FreeProperty(properties_default); + MEM_freeN(properties_default); + } } } @@ -1354,7 +1429,7 @@ void WM_keymap_restore_item_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapIt if (orig) { /* restore to original */ - if (strcmp(orig->idname, kmi->idname) != 0) { + if (!STREQ(orig->idname, kmi->idname)) { BLI_strncpy(kmi->idname, orig->idname, sizeof(kmi->idname)); WM_keymap_properties_reset(kmi, NULL); } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 68aad2dbda6..6f9646f35a1 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -38,8 +38,11 @@ #include <stdio.h> #include <stddef.h> #include <assert.h> +#include <errno.h> -#include "GHOST_C-api.h" +#ifdef WIN32 +# include "GHOST_C-api.h" +#endif #include "MEM_guardedalloc.h" @@ -58,12 +61,14 @@ #include "BLI_blenlib.h" #include "BLI_dial.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ +#include "BLI_linklist_stack.h" #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLO_readfile.h" +#include "BKE_appdir.h" #include "BKE_autoexec.h" #include "BKE_blender.h" #include "BKE_brush.h" @@ -72,12 +77,14 @@ #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" /* BKE_ST_MAXNAME */ +#include "BKE_unit.h" #include "BKE_utildefines.h" #include "BKE_idcode.h" @@ -90,15 +97,19 @@ #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" +#include "ED_numinput.h" #include "ED_screen.h" #include "ED_util.h" #include "ED_view3d.h" +#include "GPU_material.h" + #include "RNA_access.h" #include "RNA_define.h" #include "RNA_enum_types.h" #include "UI_interface.h" +#include "UI_interface_icons.h" #include "UI_resources.h" #include "WM_api.h" @@ -147,9 +158,9 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) } /* caller must free */ -GHashIterator *WM_operatortype_iter(void) +void WM_operatortype_iter(GHashIterator *ghi) { - return BLI_ghashIterator_new(global_ops_hash); + BLI_ghashIterator_init(ghi, global_ops_hash); } /* all ops in 1 list (for time being... needs evaluation later) */ @@ -494,6 +505,27 @@ bool WM_operatortype_remove(const char *idname) return true; } +/** + * Remove memory of all previously executed tools. + */ +void WM_operatortype_last_properties_clear_all(void) +{ + GHashIterator iter; + + for (WM_operatortype_iter(&iter); + (!BLI_ghashIterator_done(&iter)); + (BLI_ghashIterator_step(&iter))) + { + wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + + if (ot->last_properties) { + IDP_FreeProperty(ot->last_properties); + MEM_freeN(ot->last_properties); + ot->last_properties = NULL; + } + } +} + /* SOME_OT_op -> some.op */ void WM_operator_py_idname(char *to, const char *from) { @@ -1052,12 +1084,13 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) return retval; } else { - pup = uiPupMenuBegin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); - layout = uiPupMenuLayout(pup); + pup = UI_popup_menu_begin(C, RNA_struct_ui_name(op->type->srna), ICON_NONE); + layout = UI_popup_menu_layout(pup); /* set this so the default execution context is the same as submenus */ uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); uiItemsFullEnumO(layout, op->type->idname, RNA_property_identifier(prop), op->ptr->data, WM_OP_EXEC_REGION_WIN, 0); - uiPupMenuEnd(C, pup); + UI_popup_menu_end(C, pup); + return OPERATOR_INTERFACE; } return OPERATOR_CANCELLED; @@ -1074,19 +1107,19 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op) uiBut *but; wmOperator *op = (wmOperator *)arg_op; - block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS); - uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU); + block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); + UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU); #if 0 /* ok, this isn't so easy... */ - uiDefBut(block, LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, uiSearchBoxWidth(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); + uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); #endif but = uiDefSearchButO_ptr(block, op->type, op->ptr->data, search, 0, ICON_VIEWZOOM, sizeof(search), - 10, 10, uiSearchBoxWidth(), UI_UNIT_Y, 0, 0, ""); + 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, ""); /* fake button, it holds space for search items */ - uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL); + uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL); - uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ + UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ wm_event_init_from_window(win, &event); event.type = EVT_BUT_OPEN; @@ -1101,8 +1134,8 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op) int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - uiPupBlock(C, wm_enum_search_menu, op); - return OPERATOR_CANCELLED; + UI_popup_block_invoke(C, wm_enum_search_menu, op); + return OPERATOR_INTERFACE; } /* Can't be used as an invoke directly, needs message arg (can be NULL) */ @@ -1119,12 +1152,12 @@ int WM_operator_confirm_message_ex(bContext *C, wmOperator *op, else properties = NULL; - pup = uiPupMenuBegin(C, title, icon); - layout = uiPupMenuLayout(pup); + pup = UI_popup_menu_begin(C, title, icon); + layout = UI_popup_menu_layout(pup); uiItemFullO_ptr(layout, op->type, message, ICON_NONE, properties, WM_OP_EXEC_REGION_WIN, 0); - uiPupMenuEnd(C, pup); + UI_popup_menu_end(C, pup); - return OPERATOR_CANCELLED; + return OPERATOR_INTERFACE; } int WM_operator_confirm_message(bContext *C, wmOperator *op, const char *message) @@ -1156,7 +1189,7 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor /* dont NULL check prop, this can only run on ops with a 'filepath' */ prop = RNA_struct_find_property(op->ptr, "filepath"); RNA_property_string_get(op->ptr, prop, filepath); - if (BKE_add_image_extension(filepath, im_format)) { + if (BKE_image_path_ensure_ext_from_imformat(filepath, im_format)) { RNA_property_string_set(op->ptr, prop, filepath); /* note, we could check for and update 'filename' here, * but so far nothing needs this. */ @@ -1194,31 +1227,32 @@ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type, if (action == FILE_SAVE) { /* note, this is only used to check if we should highlight the filename area red when the * filepath is an existing file. */ - prop = RNA_def_boolean(ot->srna, "check_existing", 1, "Check Existing", "Check and warn on overwriting existing files"); + prop = RNA_def_boolean(ot->srna, "check_existing", true, "Check Existing", + "Check and warn on overwriting existing files"); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } - prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE), "Filter .blend files", ""); + prop = RNA_def_boolean(ot->srna, "filter_blender", (filter & FILE_TYPE_BLENDER) != 0, "Filter .blend files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & BLENDERFILE_BACKUP), "Filter .blend files", ""); + prop = RNA_def_boolean(ot->srna, "filter_backup", (filter & FILE_TYPE_BLENDER_BACKUP) != 0, "Filter .blend files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE), "Filter image files", ""); + prop = RNA_def_boolean(ot->srna, "filter_image", (filter & FILE_TYPE_IMAGE) != 0, "Filter image files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE), "Filter movie files", ""); + prop = RNA_def_boolean(ot->srna, "filter_movie", (filter & FILE_TYPE_MOVIE) != 0, "Filter movie files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE), "Filter python files", ""); + prop = RNA_def_boolean(ot->srna, "filter_python", (filter & FILE_TYPE_PYSCRIPT) != 0, "Filter python files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE), "Filter font files", ""); + prop = RNA_def_boolean(ot->srna, "filter_font", (filter & FILE_TYPE_FTFONT) != 0, "Filter font files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE), "Filter sound files", ""); + prop = RNA_def_boolean(ot->srna, "filter_sound", (filter & FILE_TYPE_SOUND) != 0, "Filter sound files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE), "Filter text files", ""); + prop = RNA_def_boolean(ot->srna, "filter_text", (filter & FILE_TYPE_TEXT) != 0, "Filter text files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & BTXFILE), "Filter btx files", ""); + prop = RNA_def_boolean(ot->srna, "filter_btx", (filter & FILE_TYPE_BTX) != 0, "Filter btx files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & COLLADAFILE), "Filter COLLADA files", ""); + prop = RNA_def_boolean(ot->srna, "filter_collada", (filter & FILE_TYPE_COLLADA) != 0, "Filter COLLADA files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE), "Filter folders", ""); + prop = RNA_def_boolean(ot->srna, "filter_folder", (filter & FILE_TYPE_FOLDER) != 0, "Filter folders", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, @@ -1307,7 +1341,7 @@ void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend) WM_operator_properties_border(ot); if (extend) { - RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } } @@ -1315,11 +1349,12 @@ void WM_operator_properties_mouse_select(wmOperatorType *ot) { PropertyRNA *prop; - prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first"); + prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", + "Extend selection instead of deselecting everything first"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from selection"); + prop = RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Remove from selection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Selection", "Toggle the selection"); + prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle Selection", "Toggle the selection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } @@ -1373,6 +1408,64 @@ wmOperator *WM_operator_last_redo(const bContext *C) return op; } +/** + * Use for drag & drop a path or name with operators invoke() function. + */ +ID *WM_operator_drop_load_path(struct bContext *C, wmOperator *op, const short idcode) +{ + ID *id = NULL; + /* check input variables */ + if (RNA_struct_property_is_set(op->ptr, "filepath")) { + const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); + char path[FILE_MAX]; + bool exists = false; + + RNA_string_get(op->ptr, "filepath", path); + + errno = 0; + + if (idcode == ID_IM) { + id = (ID *)BKE_image_load_exists_ex(path, &exists); + } + else { + BLI_assert(0); + } + + if (!id) { + BKE_reportf(op->reports, RPT_ERROR, "Cannot read %s '%s': %s", + BKE_idcode_to_name(idcode), path, + errno ? strerror(errno) : TIP_("unsupported format")); + return NULL; + } + + if (is_relative_path ) { + if (exists == false) { + Main *bmain = CTX_data_main(C); + + if (idcode == ID_IM) { + BLI_path_rel(((Image *)id)->name, bmain->name); + } + else { + BLI_assert(0); + } + } + } + } + else if (RNA_struct_property_is_set(op->ptr, "name")) { + char name[MAX_ID_NAME - 2]; + RNA_string_get(op->ptr, "name", name); + id = BKE_libblock_find_name(idcode, name); + if (!id) { + BKE_reportf(op->reports, RPT_ERROR, "%s '%s' not found", + BKE_idcode_to_name(idcode), name); + return NULL; + } + id_us_plus(id); + } + + return id; +} + static void wm_block_redo_cb(bContext *C, void *arg_op, int UNUSED(arg_event)) { wmOperator *op = arg_op; @@ -1404,19 +1497,19 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) wmOperator *op = arg_op; uiBlock *block; uiLayout *layout; - uiStyle *style = UI_GetStyle(); + uiStyle *style = UI_style_get(); int width = 15 * UI_UNIT_X; - block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); - uiBlockClearFlag(block, UI_BLOCK_LOOP); - uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT); + block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + UI_block_flag_disable(block, UI_BLOCK_LOOP); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT); /* if register is not enabled, the operator gets freed on OPERATOR_FINISHED * ui_apply_but_funcs_after calls ED_undo_operator_repeate_cb and crashes */ assert(op->type->flag & OPTYPE_REGISTER); - uiBlockSetHandleFunc(block, wm_block_redo_cb, arg_op); - layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, UI_UNIT_Y, 0, style); + UI_block_func_handle_set(block, wm_block_redo_cb, arg_op); + layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, width, UI_UNIT_Y, 0, style); if (op == WM_operator_last_redo(C)) if (!WM_operator_check_ui_enabled(C, op->type->name)) @@ -1431,7 +1524,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op) uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); } - uiPopupBoundsBlock(block, 4, 0, 0); + UI_block_bounds_set_popup(block, 4, 0, 0); return block; } @@ -1458,7 +1551,7 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2) /* in this case, wm_operator_ui_popup_cancel wont run */ MEM_freeN(data); - uiPupBlockClose(C, block); + UI_popup_block_close(C, block); } static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg)) @@ -1482,23 +1575,23 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) wmOperator *op = data->op; uiBlock *block; uiLayout *layout; - uiStyle *style = UI_GetStyle(); + uiStyle *style = UI_style_get(); - block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); - uiBlockClearFlag(block, UI_BLOCK_LOOP); + block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + UI_block_flag_disable(block, UI_BLOCK_LOOP); /* intentionally don't use 'UI_BLOCK_MOVEMOUSE_QUIT', some dialogues have many items * where quitting by accident is very annoying */ - uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN); - layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); + layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); - uiBlockSetFunc(block, dialog_check_cb, op, NULL); + UI_block_func_set(block, dialog_check_cb, op, NULL); uiLayoutOperatorButs(C, layout, op, NULL, 'H', UI_LAYOUT_OP_SHOW_TITLE); /* clear so the OK button is left alone */ - uiBlockSetFunc(block, NULL, NULL, NULL); + UI_block_func_set(block, NULL, NULL, NULL); /* new column so as not to interfere with custom layouts [#26436] */ { @@ -1509,12 +1602,12 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData) col = uiLayoutColumn(layout, false); col_block = uiLayoutGetBlock(col); /* Create OK button, the callback of which will execute op */ - btn = uiDefBut(col_block, BUT, 0, IFACE_("OK"), 0, -30, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); - uiButSetFunc(btn, dialog_exec_cb, data, col_block); + btn = uiDefBut(col_block, UI_BTYPE_BUT, 0, IFACE_("OK"), 0, -30, 0, UI_UNIT_Y, NULL, 0, 0, 0, 0, ""); + UI_but_func_set(btn, dialog_exec_cb, data, col_block); } /* center around the mouse */ - uiPopupBoundsBlock(block, 4, data->width / -2, data->height / 2); + UI_block_bounds_set_popup(block, 4, data->width / -2, data->height / 2); return block; } @@ -1525,18 +1618,18 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData) wmOperator *op = data->op; uiBlock *block; uiLayout *layout; - uiStyle *style = UI_GetStyle(); + uiStyle *style = UI_style_get(); - block = uiBeginBlock(C, ar, __func__, UI_EMBOSS); - uiBlockClearFlag(block, UI_BLOCK_LOOP); - uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT); + block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + UI_block_flag_disable(block, UI_BLOCK_LOOP); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_MOVEMOUSE_QUIT); - layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); + layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style); /* since ui is defined the auto-layout args are not used */ uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0); - uiPopupBoundsBlock(block, 4, 0, 0); + UI_block_bounds_set_popup(block, 4, 0, 0); return block; } @@ -1577,14 +1670,14 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height) data->width = width; data->height = height; data->free_op = true; /* if this runs and gets registered we may want not to free it */ - uiPupBlockEx(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data); + UI_popup_block_ex(C, wm_operator_ui_create, NULL, wm_operator_ui_popup_cancel, data); return OPERATOR_RUNNING_MODAL; } /** * For use by #WM_operator_props_popup_call, #WM_operator_props_popup only. * - * \note operator menu needs undo flag enabled , for redo callback */ + * \note operator menu needs undo flag enabled, for redo callback */ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op, const bool do_call, const bool do_redo) { @@ -1607,7 +1700,7 @@ static int wm_operator_props_popup_ex(bContext *C, wmOperator *op, if (!do_redo || !(U.uiflag & USER_GLOBALUNDO)) return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, UI_UNIT_Y); - uiPupBlockEx(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op); + UI_popup_block_ex(C, wm_block_create_redo, NULL, wm_block_redo_cancel_cb, op); if (do_call) wm_block_redo_cb(C, op, 0); @@ -1647,7 +1740,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width, int h data->free_op = true; /* if this runs and gets registered we may want not to free it */ /* op is not executed until popup OK but is clicked */ - uiPupBlockEx(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data); + UI_popup_block_ex(C, wm_block_dialog_create, wm_operator_ui_popup_ok, wm_operator_ui_popup_cancel, data); return OPERATOR_RUNNING_MODAL; } @@ -1665,7 +1758,7 @@ int WM_operator_redo_popup(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - uiPupBlock(C, wm_block_create_redo, op); + UI_popup_block_invoke(C, wm_block_create_redo, op); return OPERATOR_CANCELLED; } @@ -1730,7 +1823,7 @@ static void WM_OT_operator_defaults(wmOperatorType *ot) static void wm_block_splash_close(bContext *C, void *arg_block, void *UNUSED(arg)) { - uiPupBlockClose(C, arg_block); + UI_popup_block_close(C, arg_block); } static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *arg_unused); @@ -1742,22 +1835,22 @@ static void wm_block_splash_refreshmenu(bContext *UNUSED(C), void *UNUSED(arg_bl /* ugh, causes crashes in other buttons, disabling for now until * a better fix */ #if 0 - uiPupBlockClose(C, arg_block); - uiPupBlock(C, wm_block_create_splash, NULL); + UI_popup_block_close(C, arg_block); + UI_popup_block_invoke(C, wm_block_create_splash, NULL); #endif } static int wm_resource_check_prev(void) { - const char *res = BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, true); + const char *res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION, true); // if (res) printf("USER: %s\n", res); #if 0 /* ignore the local folder */ if (res == NULL) { /* with a local dir, copying old files isn't useful since local dir get priority for config */ - res = BLI_get_folder_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, true); + res = BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_LOCAL, BLENDER_VERSION, true); } #endif @@ -1766,7 +1859,7 @@ static int wm_resource_check_prev(void) return false; } else { - return (BLI_get_folder_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, true) != NULL); + return (BKE_appdir_folder_id_version(BLENDER_RESOURCE_PATH_USER, BLENDER_VERSION - 1, true) != NULL); } } @@ -1775,7 +1868,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar uiBlock *block; uiBut *but; uiLayout *layout, *split, *col; - uiStyle *style = UI_GetStyle(); + uiStyle *style = UI_style_get(); const struct RecentFile *recent; int i; MenuType *mt = WM_menutype_find("USERPREF_MT_splash", true); @@ -1821,17 +1914,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar } #endif - block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS); + block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); /* note on UI_BLOCK_NO_WIN_CLIP, the window size is not always synchronized * with the OS when the splash shows, window clipping in this case gives * ugly results and clipping the splash isn't useful anyway, just disable it [#32938] */ - uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); + UI_block_flag_enable(block, UI_BLOCK_KEEP_OPEN | UI_BLOCK_NO_WIN_CLIP); /* XXX splash scales with pixelsize, should become widget-units */ - but = uiDefBut(block, BUT_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.pixelsize * 501, U.pixelsize * 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */ - uiButSetFunc(but, wm_block_splash_close, block, NULL); - uiBlockSetFunc(block, wm_block_splash_refreshmenu, block, NULL); + but = uiDefBut(block, UI_BTYPE_IMAGE, 0, "", 0, 0.5f * U.widget_unit, U.pixelsize * 501, U.pixelsize * 282, ibuf, 0.0, 0.0, 0, 0, ""); /* button owns the imbuf now */ + UI_but_func_set(but, wm_block_splash_close, block, NULL); + UI_block_func_set(block, wm_block_splash_refreshmenu, block, NULL); /* label for 'a' bugfix releases, or 'Release Candidate 1'... * avoids recreating splash for version updates */ @@ -1849,32 +1942,32 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar int w = 240; /* hack to have text draw 'text_sel' */ - uiBlockSetEmboss(block, UI_EMBOSSN); - but = uiDefBut(block, LABEL, 0, version_suffix, x * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + but = uiDefBut(block, UI_BTYPE_LABEL, 0, version_suffix, x * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); /* XXX, set internal flag - UI_SELECT */ - uiButSetFlag(but, 1); - uiBlockSetEmboss(block, UI_EMBOSS); + UI_but_flag_enable(but, 1); + UI_block_emboss_set(block, UI_EMBOSS); } #ifdef WITH_BUILDINFO if (build_commit_timestamp != 0) { - uiDefBut(block, LABEL, 0, date_buf, U.pixelsize * 494 - date_width, U.pixelsize * 270, date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL); + 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); label_delta = 12; } - uiDefBut(block, 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); + 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); 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, 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); + 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); } #endif /* WITH_BUILDINFO */ - layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style); + layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 10, 2, U.pixelsize * 480, U.pixelsize * 110, 0, style); - uiBlockSetEmboss(block, UI_EMBOSS); + UI_block_emboss_set(block, UI_EMBOSS); /* show the splash menu (containing interaction presets), using python */ if (mt) { Menu menu = {NULL}; @@ -1886,7 +1979,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar // uiItemM(layout, C, "USERPREF_MT_keyconfigs", U.keyconfigstr, ICON_NONE); } - uiBlockSetEmboss(block, UI_EMBOSSP); + UI_block_emboss_set(block, UI_EMBOSS_PULLDOWN); uiLayoutSetOperatorContext(layout, WM_OP_EXEC_REGION_WIN); split = uiLayoutSplit(layout, 0.0f, false); @@ -1902,7 +1995,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar BLENDER_VERSION / 100, BLENDER_VERSION % 100); uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url); uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url", - "http://wiki.blender.org/index.php/Doc:2.6/Manual"); + "http://www.blender.org/manual"); uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org"); if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d" @@ -1935,14 +2028,22 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session"); uiItemL(col, "", ICON_NONE); - uiCenteredBoundsBlock(block, 0); + mt = WM_menutype_find("USERPREF_MT_splash_footer", false); + if (mt) { + Menu menu = {NULL}; + menu.layout = uiLayoutColumn(layout, false); + menu.type = mt; + mt->draw(C, &menu); + } + + UI_block_bounds_set_centered(block, 0); return block; } static int wm_splash_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - uiPupBlock(C, wm_block_create_splash, NULL); + UI_popup_block_invoke(C, wm_block_create_splash, NULL); return OPERATOR_FINISHED; } @@ -1967,16 +2068,16 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_ uiBlock *block; uiBut *but; - block = uiBeginBlock(C, ar, "_popup", UI_EMBOSS); - uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU); + block = UI_block_begin(C, ar, "_popup", UI_EMBOSS); + UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU); - but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, uiSearchBoxWidth(), UI_UNIT_Y, 0, 0, ""); - uiOperatorSearch_But(but); + but = uiDefSearchBut(block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, ""); + UI_but_func_operator_search(but); /* fake button, it holds space for search items */ - uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL); + uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL); - uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ + UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */ wm_event_init_from_window(win, &event); event.type = EVT_BUT_OPEN; @@ -1995,9 +2096,9 @@ static int wm_search_menu_exec(bContext *UNUSED(C), wmOperator *UNUSED(op)) static int wm_search_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - uiPupBlock(C, wm_block_search_menu, op); + UI_popup_block_invoke(C, wm_block_search_menu, op); - return OPERATOR_CANCELLED; + return OPERATOR_INTERFACE; } /* op->poll */ @@ -2036,9 +2137,7 @@ static int wm_call_menu_exec(bContext *C, wmOperator *op) char idname[BKE_ST_MAXNAME]; RNA_string_get(op->ptr, "name", idname); - uiPupMenuInvoke(C, idname, op->reports); - - return OPERATOR_CANCELLED; + return UI_popup_menu_invoke(C, idname, op->reports); } static void WM_OT_call_menu(wmOperatorType *ot) @@ -2060,9 +2159,7 @@ static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *e char idname[BKE_ST_MAXNAME]; RNA_string_get(op->ptr, "name", idname); - uiPieMenuInvoke(C, idname, event); - - return OPERATOR_CANCELLED; + return UI_pie_menu_invoke(C, idname, event); } static int wm_call_pie_menu_exec(bContext *C, wmOperator *op) @@ -2070,9 +2167,7 @@ static int wm_call_pie_menu_exec(bContext *C, wmOperator *op) char idname[BKE_ST_MAXNAME]; RNA_string_get(op->ptr, "name", idname); - uiPieMenuInvoke(C, idname, CTX_wm_window(C)->eventstate); - - return OPERATOR_CANCELLED; + return UI_pie_menu_invoke(C, idname, CTX_wm_window(C)->eventstate); } static void WM_OT_call_menu_pie(wmOperatorType *ot) @@ -2374,7 +2469,7 @@ static void WM_OT_open_mainfile(wmOperatorType *ot) ot->ui = wm_open_mainfile_ui; /* omit window poll so this can work in background mode */ - WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file"); @@ -2561,6 +2656,13 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) lib = mainl->curlib; BLI_assert(lib); + if (mainl->versionfile < 250) { + BKE_reportf(op->reports, RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, mainl->subversionfile); + } + if (totfiles == 0) { BLO_library_append_named_part_ex(C, mainl, &bh, name, idcode, flag); } @@ -2590,7 +2692,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* recreate dependency graph to include new objects */ DAG_scene_relations_rebuild(bmain, scene); - + + /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ + GPU_materials_free(); BLO_blendhandle_close(bh); /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ @@ -2634,7 +2738,7 @@ static void WM_OT_link(wmOperatorType *ot) ot->flag |= OPTYPE_UNDO; WM_operator_properties_filesel( - ot, FOLDERFILE | BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); @@ -2654,7 +2758,7 @@ static void WM_OT_append(wmOperatorType *ot) ot->flag |= OPTYPE_UNDO; WM_operator_properties_filesel( - ot, FOLDERFILE | BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE, + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_LOADLIB, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY); @@ -2667,7 +2771,7 @@ void WM_recover_last_session(bContext *C, ReportList *reports) { char filepath[FILE_MAX]; - BLI_make_file_string("/", filepath, BLI_temp_dir_base(), BLENDER_QUIT_FILE); + BLI_make_file_string("/", filepath, BKE_tempdir_base(), BLENDER_QUIT_FILE); /* if reports==NULL, it's called directly without operator, we add a quick check here */ if (reports || BLI_exists(filepath)) { G.fileflags |= G_FILE_RECOVER; @@ -2746,7 +2850,7 @@ static void WM_OT_recover_auto_save(wmOperatorType *ot) ot->exec = wm_recover_auto_save_exec; ot->invoke = wm_recover_auto_save_invoke; - WM_operator_properties_filesel(ot, BLENDERFILE, FILE_BLENDER, FILE_OPENFILE, + WM_operator_properties_filesel(ot, FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, FILE_LONGDISPLAY); } @@ -2763,9 +2867,9 @@ static void save_set_compress(wmOperator *op) { if (!RNA_struct_property_is_set(op->ptr, "compress")) { if (G.save_over) /* keep flag for existing file */ - RNA_boolean_set(op->ptr, "compress", G.fileflags & G_FILE_COMPRESS); + RNA_boolean_set(op->ptr, "compress", (G.fileflags & G_FILE_COMPRESS) != 0); else /* use userdef for new file */ - RNA_boolean_set(op->ptr, "compress", U.flag & USER_FILECOMPRESS); + RNA_boolean_set(op->ptr, "compress", (U.flag & USER_FILECOMPRESS) != 0); } } @@ -2824,6 +2928,8 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) (RNA_struct_find_property(op->ptr, "use_mesh_compat") && RNA_boolean_get(op->ptr, "use_mesh_compat")), G_FILE_MESH_COMPAT); +#else +# error "don't remove by accident" #endif if (wm_file_write(C, path, fileflags, op->reports) != 0) @@ -2862,16 +2968,16 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot) ot->check = blend_save_check; /* omit window poll so this can work in background mode */ - WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); - RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file"); - RNA_def_boolean(ot->srna, "relative_remap", 1, "Remap Relative", + RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file"); + RNA_def_boolean(ot->srna, "relative_remap", true, "Remap Relative", "Remap relative paths when saving in a different directory"); - prop = RNA_def_boolean(ot->srna, "copy", 0, "Save Copy", + prop = RNA_def_boolean(ot->srna, "copy", false, "Save Copy", "Save a copy of the actual working state but does not make saved file active"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); #ifdef USE_BMESH_SAVE_AS_COMPAT - RNA_def_boolean(ot->srna, "use_mesh_compat", 0, "Legacy Mesh Format", + RNA_def_boolean(ot->srna, "use_mesh_compat", false, "Legacy Mesh Format", "Save using legacy mesh format (no ngons) - WARNING: only saves tris and quads, other ngons will " "be lost (no implicit triangulation)"); #endif @@ -2938,10 +3044,11 @@ static void WM_OT_save_mainfile(wmOperatorType *ot) ot->check = blend_save_check; /* omit window poll so this can work in background mode */ - WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_SAVE, + WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY); - RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file"); - RNA_def_boolean(ot->srna, "relative_remap", 0, "Remap Relative", "Remap relative paths when saving in a different directory"); + RNA_def_boolean(ot->srna, "compress", false, "Compress", "Write compressed .blend file"); + RNA_def_boolean(ot->srna, "relative_remap", false, "Remap Relative", + "Remap relative paths when saving in a different directory"); } static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot) @@ -3064,14 +3171,16 @@ static int border_apply_rect(wmOperator *op) static int border_apply(bContext *C, wmOperator *op, int gesture_mode) { + PropertyRNA *prop; + int retval; if (!border_apply_rect(op)) return 0; /* XXX weak; border should be configured for this without reading event types */ - if (RNA_struct_find_property(op->ptr, "gesture_mode")) { - RNA_int_set(op->ptr, "gesture_mode", gesture_mode); + if ((prop = RNA_struct_find_property(op->ptr, "gesture_mode"))) { + RNA_property_int_set(op->ptr, prop, gesture_mode); } retval = op->type->exec(C, op); @@ -3391,6 +3500,8 @@ void wm_tweakevent_test(bContext *C, wmEvent *event, int action) int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + PropertyRNA *prop; + op->customdata = WM_gesture_new(C, event, WM_GESTURE_LASSO); /* add modal handler */ @@ -3398,8 +3509,8 @@ int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event) wm_gesture_tag_redraw(C); - if (RNA_struct_find_property(op->ptr, "cursor")) { - WM_cursor_modal_set(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); + if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) { + WM_cursor_modal_set(CTX_wm_window(C), RNA_property_int_get(op->ptr, prop)); } return OPERATOR_RUNNING_MODAL; @@ -3407,6 +3518,8 @@ int WM_gesture_lasso_invoke(bContext *C, wmOperator *op, const wmEvent *event) int WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + PropertyRNA *prop; + op->customdata = WM_gesture_new(C, event, WM_GESTURE_LINES); /* add modal handler */ @@ -3414,8 +3527,8 @@ int WM_gesture_lines_invoke(bContext *C, wmOperator *op, const wmEvent *event) wm_gesture_tag_redraw(C); - if (RNA_struct_find_property(op->ptr, "cursor")) { - WM_cursor_modal_set(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); + if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) { + WM_cursor_modal_set(CTX_wm_window(C), RNA_property_int_get(op->ptr, prop)); } return OPERATOR_RUNNING_MODAL; @@ -3621,6 +3734,8 @@ static int straightline_apply(bContext *C, wmOperator *op) int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + PropertyRNA *prop; + op->customdata = WM_gesture_new(C, event, WM_GESTURE_STRAIGHTLINE); /* add modal handler */ @@ -3628,8 +3743,8 @@ int WM_gesture_straightline_invoke(bContext *C, wmOperator *op, const wmEvent *e wm_gesture_tag_redraw(C); - if (RNA_struct_find_property(op->ptr, "cursor")) { - WM_cursor_modal_set(CTX_wm_window(C), RNA_int_get(op->ptr, "cursor")); + if ((prop = RNA_struct_find_property(op->ptr, "cursor"))) { + WM_cursor_modal_set(CTX_wm_window(C), RNA_property_int_get(op->ptr, prop)); } return OPERATOR_RUNNING_MODAL; @@ -3709,9 +3824,10 @@ void WM_OT_straightline_gesture(wmOperatorType *ot) /* *********************** radial control ****************** */ -#define WM_RADIAL_CONTROL_DISPLAY_SIZE 200 -#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE 35 +#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * U.pixelsize) +#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize) #define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) +#define WM_RADIAL_CONTROL_HEADER_LENGTH 180 #define WM_RADIAL_MAX_STR 6 typedef struct { @@ -3729,8 +3845,24 @@ typedef struct { ListBase orig_paintcursors; bool use_secondary_tex; void *cursor; + NumInput num_input; } RadialControl; +static void radial_control_update_header(wmOperator *op, bContext *C) +{ + RadialControl *rc = op->customdata; + char msg[WM_RADIAL_CONTROL_HEADER_LENGTH]; + ScrArea *sa = CTX_wm_area(C); + Scene *scene = CTX_data_scene(C); + + if (sa && hasNumInput(&rc->num_input)) { + char num_str[NUM_STR_REP_LEN]; + outputNumInput(&rc->num_input, num_str, &scene->unit); + BLI_snprintf(msg, WM_RADIAL_CONTROL_HEADER_LENGTH, "%s: %s", RNA_property_ui_name(rc->prop), num_str); + ED_area_headerprint(sa, msg); + } +} + static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event) { float d[2] = {0, 0}; @@ -3742,8 +3874,9 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e switch (rc->subtype) { case PROP_NONE: case PROP_DISTANCE: + case PROP_PERCENTAGE: case PROP_PIXEL: - d[0] = rc->initial_value; + d[0] = rc->initial_value * U.pixelsize; break; case PROP_FACTOR: d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; @@ -3837,7 +3970,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd { RadialControl *rc = customdata; ARegion *ar = CTX_wm_region(C); - uiStyle *style = UI_GetStyle(); + uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; const int fontid = fstyle->uifont_id; short fstyle_points = fstyle->points; @@ -3850,9 +3983,10 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd switch (rc->subtype) { case PROP_NONE: case PROP_DISTANCE: + case PROP_PERCENTAGE: case PROP_PIXEL: - r1 = rc->current_value; - r2 = rc->initial_value; + r1 = rc->current_value * U.pixelsize; + r2 = rc->initial_value * U.pixelsize; tex_radius = r1; alpha = 0.75; break; @@ -3877,11 +4011,6 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd break; } - /* adjust for DPI, like BKE_brush_size_get */ - r1 *= U.pixelsize; - r2 *= U.pixelsize; - tex_radius *= U.pixelsize; - /* Keep cursor in the original place */ x = rc->initial_mouse[0] - ar->winrct.xmin; y = rc->initial_mouse[1] - ar->winrct.ymin; @@ -3989,7 +4118,7 @@ static int radial_control_get_path(PointerRNA *ctx_ptr, wmOperator *op, PropertyType prop_type = RNA_property_type(*r_prop); if (((flags & RC_PROP_REQUIRE_BOOL) && (prop_type != PROP_BOOLEAN)) || - ((flags & RC_PROP_REQUIRE_FLOAT) && prop_type != PROP_FLOAT)) + ((flags & RC_PROP_REQUIRE_FLOAT) && (prop_type != PROP_FLOAT))) { MEM_freeN(str); BKE_reportf(op->reports, RPT_ERROR, "Property from path '%s' is not a float", name); @@ -4113,14 +4242,21 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve return OPERATOR_CANCELLED; } + /* initialize numerical input */ + initNumInput(&rc->num_input); + rc->num_input.idx_max = 0; + rc->num_input.val_flag[0] |= NUM_NO_NEGATIVE; + rc->num_input.unit_sys = USER_UNIT_NONE; + rc->num_input.unit_type[0] = B_UNIT_LENGTH; + /* get subtype of property */ rc->subtype = RNA_property_subtype(rc->prop); - if (!ELEM(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) { - BKE_report(op->reports, RPT_ERROR, "Property must be a none, distance, a factor, or an angle"); + if (!ELEM(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_PERCENTAGE, PROP_ANGLE, PROP_PIXEL)) { + BKE_report(op->reports, RPT_ERROR, "Property must be a none, distance, factor, percentage, angle, or pixel"); MEM_freeN(rc); return OPERATOR_CANCELLED; } - + rc->current_value = rc->initial_value; radial_control_set_initial_mouse(rc, event); radial_control_set_tex(rc); @@ -4157,11 +4293,16 @@ static void radial_control_cancel(bContext *C, wmOperator *op) { RadialControl *rc = op->customdata; wmWindowManager *wm = CTX_wm_manager(C); + ScrArea *sa = CTX_wm_area(C); if (rc->dial) { MEM_freeN(rc->dial); rc->dial = NULL; } + + if (sa) { + ED_area_headerprint(sa, NULL); + } WM_paint_cursor_end(wm, rc->cursor); @@ -4185,125 +4326,183 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even float delta[2], ret = OPERATOR_RUNNING_MODAL; bool snap; float angle_precision = 0.0f; + const bool has_numInput = hasNumInput(&rc->num_input); + bool handled = false; + float numValue; /* TODO: fix hardcoded events */ snap = event->ctrl != 0; - switch (event->type) { - case MOUSEMOVE: - if (rc->slow_mode) { - if (rc->subtype == PROP_ANGLE) { - float position[2] = {event->x, event->y}; - - /* calculate the initial angle here first */ - delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; - delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; - - /* precision angle gets calculated from dial and gets added later */ - angle_precision = -0.1f * BLI_dial_angle(rc->dial, position); - } - else { - delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; - delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; - - if (rc->zoom_prop) { - RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + /* Modal numinput active, try to handle numeric inputs first... */ + if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &rc->num_input, event)) { + handled = true; + applyNumInput(&rc->num_input, &numValue); + + if (rc->subtype == PROP_ANGLE) { + numValue = DEG2RADF(numValue); + numValue = fmod(numValue, 2.0f * (float)M_PI); + if (numValue < 0.0f) + numValue += 2.0f * (float)M_PI; + } + + CLAMP(numValue, rc->min_value, rc->max_value); + new_value = numValue; + + radial_control_set_value(rc, new_value); + rc->current_value = new_value; + radial_control_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } + else { + handled = false; + switch (event->type) { + case ESCKEY: + case RIGHTMOUSE: + /* canceled; restore original value */ + radial_control_set_value(rc, rc->initial_value); + ret = OPERATOR_CANCELLED; + break; + + case LEFTMOUSE: + case PADENTER: + case RETKEY: + /* done; value already set */ + RNA_property_update(C, &rc->ptr, rc->prop); + ret = OPERATOR_FINISHED; + break; + + case MOUSEMOVE: + if (!has_numInput) { + if (rc->slow_mode) { + if (rc->subtype == PROP_ANGLE) { + float position[2] = {event->x, event->y}; + + /* calculate the initial angle here first */ + delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; + delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + + /* precision angle gets calculated from dial and gets added later */ + angle_precision = -0.1f * BLI_dial_angle(rc->dial, position); + } + else { + delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0]; + delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1]; + + if (rc->zoom_prop) { + RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = len_v2(delta); + + delta[0] = event->x - rc->slow_mouse[0]; + delta[1] = event->y - rc->slow_mouse[1]; + + if (rc->zoom_prop) { + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = dist + 0.1f * (delta[0] + delta[1]); + } } - - dist = len_v2(delta); - - delta[0] = event->x - rc->slow_mouse[0]; - delta[1] = event->y - rc->slow_mouse[1]; - - if (rc->zoom_prop) { - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + else { + delta[0] = rc->initial_mouse[0] - event->x; + delta[1] = rc->initial_mouse[1] - event->y; + + if (rc->zoom_prop) { + RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); + delta[0] /= zoom[0]; + delta[1] /= zoom[1]; + } + + dist = len_v2(delta); } - - dist = dist + 0.1f * (delta[0] + delta[1]); + + /* calculate new value and apply snapping */ + switch (rc->subtype) { + case PROP_NONE: + case PROP_DISTANCE: + case PROP_PERCENTAGE: + case PROP_PIXEL: + new_value = dist; + if (snap) new_value = ((int)new_value + 5) / 10 * 10; + new_value /= U.pixelsize; + break; + case PROP_FACTOR: + new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH; + if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; + break; + case PROP_ANGLE: + new_value = atan2f(delta[1], delta[0]) + (float)M_PI + angle_precision; + new_value = fmod(new_value, 2.0f * (float)M_PI); + if (new_value < 0.0f) + new_value += 2.0f * (float)M_PI; + if (snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10); + break; + default: + new_value = dist; /* dummy value, should this ever happen? - campbell */ + break; + } + + /* clamp and update */ + CLAMP(new_value, rc->min_value, rc->max_value); + radial_control_set_value(rc, new_value); + rc->current_value = new_value; + handled = true; + break; } - } - else { - delta[0] = rc->initial_mouse[0] - event->x; - delta[1] = rc->initial_mouse[1] - event->y; + break; - if (rc->zoom_prop) { - RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom); - delta[0] /= zoom[0]; - delta[1] /= zoom[1]; + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + { + if (event->val == KM_PRESS) { + rc->slow_mouse[0] = event->x; + rc->slow_mouse[1] = event->y; + rc->slow_mode = true; + if (rc->subtype == PROP_ANGLE) { + float initial_position[2] = {UNPACK2(rc->initial_mouse)}; + float current_position[2] = {UNPACK2(rc->slow_mouse)}; + rc->dial = BLI_dial_initialize(initial_position, 0.0f); + /* immediately set the position to get a an initial direction */ + BLI_dial_angle(rc->dial, current_position); + } + handled = true; } - - dist = len_v2(delta); + if (event->val == KM_RELEASE) { + rc->slow_mode = false; + handled = true; + if (rc->dial) { + MEM_freeN(rc->dial); + rc->dial = NULL; + } + } + break; } + } - /* calculate new value and apply snapping */ - switch (rc->subtype) { - case PROP_NONE: - case PROP_DISTANCE: - case PROP_PIXEL: - new_value = dist; - if (snap) new_value = ((int)new_value + 5) / 10 * 10; - break; - case PROP_FACTOR: - new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH; - if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f; - break; - case PROP_ANGLE: - new_value = atan2f(delta[1], delta[0]) + M_PI + angle_precision; - new_value = fmod(new_value, 2.0f * (float)M_PI); - if (new_value < 0.0f) - new_value += 2.0f * (float)M_PI; - if (snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10); - break; - default: - new_value = dist; /* dummy value, should this ever happen? - campbell */ - break; + /* Modal numinput inactive, try to handle numeric inputs last... */ + if (!handled && event->val == KM_PRESS && handleNumInput(C, &rc->num_input, event)) { + applyNumInput(&rc->num_input, &numValue); + + if (rc->subtype == PROP_ANGLE) { + numValue = DEG2RADF(numValue); + numValue = fmod(numValue, 2.0f * (float)M_PI); + if (numValue < 0.0f) + numValue += 2.0f * (float)M_PI; } - /* clamp and update */ - CLAMP(new_value, rc->min_value, rc->max_value); + CLAMP(numValue, rc->min_value, rc->max_value); + new_value = numValue; + radial_control_set_value(rc, new_value); - rc->current_value = new_value; - break; - - case ESCKEY: - case RIGHTMOUSE: - /* canceled; restore original value */ - radial_control_set_value(rc, rc->initial_value); - ret = OPERATOR_CANCELLED; - break; - - case LEFTMOUSE: - case PADENTER: - /* done; value already set */ - RNA_property_update(C, &rc->ptr, rc->prop); - ret = OPERATOR_FINISHED; - break; - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: - if (event->val == KM_PRESS) { - rc->slow_mouse[0] = event->x; - rc->slow_mouse[1] = event->y; - rc->slow_mode = true; - if (rc->subtype == PROP_ANGLE) { - float initial_position[2] = {UNPACK2(rc->initial_mouse)}; - float current_position[2] = {UNPACK2(rc->slow_mouse)}; - rc->dial = BLI_dial_initialize(initial_position, 0.0f); - /* immediately set the position to get a an initial direction */ - BLI_dial_angle(rc->dial, current_position); - } - } - if (event->val == KM_RELEASE) { - rc->slow_mode = false; - if (rc->dial) { - MEM_freeN(rc->dial); - rc->dial = NULL; - } - } - break; + rc->current_value = new_value; + radial_control_update_header(op, C); + return OPERATOR_RUNNING_MODAL; + } } ED_region_tag_redraw(CTX_wm_region(C)); @@ -4343,7 +4542,7 @@ static void WM_OT_radial_control(wmOperatorType *ot) RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control"); - RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture"); + RNA_def_boolean(ot->srna, "secondary_tex", false, "Secondary Texture", "Tweak brush secondary/mask texture"); } /* ************************** timer for testing ***************** */ @@ -4525,6 +4724,90 @@ static void WM_OT_dependency_relations(wmOperatorType *ot) ot->exec = dependency_relations_exec; } +/* *************************** Mat/tex/etc. previews generation ************* */ + +typedef struct PreviewsIDEnsureStack { + Scene *scene; + + BLI_LINKSTACK_DECLARE(id_stack, ID *); +} PreviewsIDEnsureStack; + +static void previews_id_ensure(bContext *C, Scene *scene, ID *id) +{ + BLI_assert(ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)); + + /* Only preview non-library datablocks, lib ones do not pertain to this .blend file! + * Same goes for ID with no user. */ + if (!id->lib && (id->us != 0)) { + UI_id_icon_render(C, scene, id, false, false); + UI_id_icon_render(C, scene, id, true, false); + } +} + +static bool previews_id_ensure_callback(void *todo_v, ID **idptr, int UNUSED(cd_flag)) +{ + PreviewsIDEnsureStack *todo = todo_v; + ID *id = *idptr; + + if (id && (id->flag & LIB_DOIT)) { + if (ELEM(GS(id->name), ID_MA, ID_TE, ID_IM, ID_WO, ID_LA)) { + previews_id_ensure(NULL, todo->scene, id); + } + id->flag &= ~LIB_DOIT; /* Tag the ID as done in any case. */ + BLI_LINKSTACK_PUSH(todo->id_stack, id); + } + + return true; +} + +static int previews_ensure_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + ListBase *lb[] = {&bmain->mat, &bmain->tex, &bmain->image, &bmain->world, &bmain->lamp, NULL}; + PreviewsIDEnsureStack preview_id_stack; + Scene *scene; + ID *id; + int i; + + /* We use LIB_DOIT to check whether we have already handled a given ID or not. */ + BKE_main_id_flag_all(bmain, LIB_DOIT, true); + + BLI_LINKSTACK_INIT(preview_id_stack.id_stack); + + for (scene = bmain->scene.first; scene; scene = scene->id.next) { + preview_id_stack.scene = scene; + id = (ID *)scene; + + do { + /* This will loop over all IDs linked by current one, render icons for them if needed, + * and add them to 'todo' preview_id_stack. */ + BKE_library_foreach_ID_link(id, previews_id_ensure_callback, &preview_id_stack, IDWALK_READONLY); + } while ((id = BLI_LINKSTACK_POP(preview_id_stack.id_stack))); + } + + BLI_LINKSTACK_FREE(preview_id_stack.id_stack); + + /* Check a last time for ID not used (fake users only, in theory), and + * do our best for those, using current scene... */ + for (i = 0; lb[i]; i++) { + for (id = lb[i]->first; id; id = id->next) { + previews_id_ensure(C, NULL, id); + } + } + + return OPERATOR_FINISHED; +} + +static void WM_OT_previews_ensure(wmOperatorType *ot) +{ + ot->name = "Refresh DataBlock Previews"; + ot->idname = "WM_OT_previews_ensure"; + ot->description = "Ensure datablock previews are available and up-to-date " + "(to be saved in .blend file, only for some types like materials, textures, etc.)"; + + ot->exec = previews_ensure_exec; +} + /* ******************************************************* */ static void operatortype_ghash_free_cb(wmOperatorType *ot) @@ -4588,6 +4871,7 @@ void wm_operatortype_init(void) #if defined(WIN32) WM_operatortype_append(WM_OT_console_toggle); #endif + WM_operatortype_append(WM_OT_previews_ensure); } /* circleselect-like modal operators */ @@ -4645,6 +4929,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "CLIP_OT_select_circle"); WM_modalkeymap_assign(keymap, "MASK_OT_select_circle"); WM_modalkeymap_assign(keymap, "NODE_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); } @@ -4741,6 +5027,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border"); WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */ WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border"); + WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_border"); } /* zoom to border modal operators */ diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index 76add2f9aac..31883cf234c 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -69,8 +69,6 @@ #include "GHOST_C-api.h" #include "BLF_api.h" -#include "wm_event_types.h" - #include "WM_api.h" /* only for WM_main_playanim */ struct PlayState; @@ -298,8 +296,8 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf glRasterPos2f(offs_x + (ps->draw_flip[0] ? span_x : 0.0f), offs_y + (ps->draw_flip[1] ? span_y : 0.0f)); - glPixelZoom(ps->zoom * ps->draw_flip[0] ? -1.0f : 1.0f, - ps->zoom * ps->draw_flip[1] ? -1.0f : 1.0f); + glPixelZoom(ps->zoom * (ps->draw_flip[0] ? -1.0f : 1.0f), + ps->zoom * (ps->draw_flip[1] ? -1.0f : 1.0f)); glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); @@ -850,6 +848,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void) static void playanim_window_open(const char *title, int posx, int posy, int sizex, int sizey) { + GHOST_GLSettings glsettings = {0}; GHOST_TUns32 scr_w, scr_h; GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &scr_w, &scr_h); @@ -862,7 +861,7 @@ static void playanim_window_open(const char *title, int posx, int posy, int size /* could optionally start fullscreen */ GHOST_kWindowStateNormal, GHOST_kDrawingContextTypeOpenGL, - false /* no stereo */, false); + glsettings); } static void playanim_window_zoom(PlayState *ps, const float zoom_offset) diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index e26bcac9b1a..4ce2415e310 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -53,7 +53,6 @@ #include "WM_api.h" #include "wm_subwindow.h" -#include "wm_window.h" /* wmSubWindow stored in wmWindow... but not exposed outside this C file */ /* it seems a bit redundant (area regions can store it too, but we keep it @@ -368,7 +367,7 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs) */ void wmOrtho2_region_pixelspace(const struct ARegion *ar) { - wmOrtho2_offset(ar->winx + 1, ar->winy + 1, -GLA_PIXEL_OFS); + wmOrtho2_offset(ar->winx, ar->winy, -0.01f); } void wmOrtho2_pixelspace(const float x, const float y) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 46a20d3bf88..4f7e5ab75b3 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -356,6 +356,7 @@ float wm_window_pixelsize(wmWindow *win) static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wmWindow *win) { GHOST_WindowHandle ghostwin; + GHOST_GLSettings glSettings = {0}; static int multisamples = -1; int scr_w, scr_h, posy; @@ -363,7 +364,12 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm * mix it, either all windows have it, or none (tested in OSX opengl) */ if (multisamples == -1) multisamples = U.ogl_multisamples; - + + glSettings.numOfAASamples = multisamples; + + if (!(U.uiflag2 & USER_OPENGL_NO_WARN_SUPPORT)) + glSettings.flags |= GHOST_glWarnSupport; + wm_get_screensize(&scr_w, &scr_h); posy = (scr_h - win->posy - win->sizey); @@ -371,8 +377,7 @@ static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wm win->posx, posy, win->sizex, win->sizey, (GHOST_TWindowState)win->windowstate, GHOST_kDrawingContextTypeOpenGL, - 0 /* no stereo */, - multisamples /* AA */); + glSettings); if (ghostwin) { GHOST_RectangleHandle bounds; @@ -1524,3 +1529,21 @@ bool WM_window_is_fullscreen(wmWindow *win) return win->windowstate == GHOST_kWindowStateFullScreen; } + +#ifdef WITH_INPUT_IME +/* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */ +void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete) +{ + BLI_assert(win); + + GHOST_BeginIME(win->ghostwin, x, win->sizey - y, w, h, complete); +} + +void wm_window_IME_end(wmWindow *win) +{ + BLI_assert(win && win->ime_data); + + GHOST_EndIME(win->ghostwin); + win->ime_data = NULL; +} +#endif /* WITH_INPUT_IME */ diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index d1a94194108..f89177a82ea 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -65,9 +65,6 @@ typedef struct wmEventHandler { struct ARegion *ui_region; /* for derived/modal handlers */ struct ARegion *ui_menu; /* for derived/modal handlers */ - /* fileselect handler re-uses modal operator data */ - struct bScreen *filescreen; /* screen it started in, to validate exec */ - /* drop box handler */ ListBase *dropboxes; diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index 7dfc2b52c33..ecc29de0e7d 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -86,10 +86,19 @@ enum { * paint and drawing tools however will want to handle these. */ INBETWEEN_MOUSEMOVE = 0x0011, +/* IME event, GHOST_kEventImeCompositionStart in ghost */ + WM_IME_COMPOSITE_START = 0x0014, +/* IME event, GHOST_kEventImeComposition in ghost */ + WM_IME_COMPOSITE_EVENT = 0x0015, +/* IME event, GHOST_kEventImeCompositionEnd in ghost */ + WM_IME_COMPOSITE_END = 0x0016, + /* *** Start of keyboard codes. *** */ /* standard keyboard. * XXX from 0x0020 to 0x00ff, and 0x012c to 0x013f for function keys! */ + + /* NOTE: these values are saved in keymap files, do not change them but just add new ones */ AKEY = 0x0061, /* 'a' */ BKEY = 0x0062, /* 'b' */ CKEY = 0x0063, /* 'c' */ @@ -299,16 +308,21 @@ enum { /* Tweak, gestures: 0x500x, 0x501x */ EVT_ACTIONZONE_AREA = 0x5000, EVT_ACTIONZONE_REGION = 0x5001, - EVT_ACTIONZONE_FULLSCREEN = 0x5002, + EVT_ACTIONZONE_FULLSCREEN = 0x5011, + + /* NOTE: these values are saved in keymap files, do not change them but just add new ones */ + /* tweak events, for L M R mousebuttons */ - EVT_TWEAK_L = 0x5003, - EVT_TWEAK_M = 0x5004, - EVT_TWEAK_R = 0x5005, + EVT_TWEAK_L = 0x5002, + EVT_TWEAK_M = 0x5003, + EVT_TWEAK_R = 0x5004, /* tweak events for action or select mousebutton */ - EVT_TWEAK_A = 0x5006, - EVT_TWEAK_S = 0x5007, + EVT_TWEAK_A = 0x5005, + EVT_TWEAK_S = 0x5006, EVT_GESTURE = 0x5010, + /* 0x5011 is taken, see EVT_ACTIONZONE_FULLSCREEN */ + /* Misc Blender internals: 0x502x */ EVT_FILESELECT = 0x5020, EVT_BUT_OPEN = 0x5021, @@ -355,10 +369,23 @@ enum { (event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \ (event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false) +/* internal helpers*/ +#define _VA_IS_EVENT_MOD2(v, a) (CHECK_TYPE_INLINE(v, wmEvent *), \ + ((v)->a)) +#define _VA_IS_EVENT_MOD3(v, a, b) \ + (_VA_IS_EVENT_MOD2(v, a) || ((v)->b)) +#define _VA_IS_EVENT_MOD4(v, a, b, c) \ + (_VA_IS_EVENT_MOD3(v, a, b) || ((v)->c)) +#define _VA_IS_EVENT_MOD5(v, a, b, c, d) \ + (_VA_IS_EVENT_MOD4(v, a, b, c) || ((v)->d)) + +/* reusable IS_EVENT_MOD(event, shift, ctrl, alt, oskey), macro */ +#define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__) /* ********** wmEvent.val ********** */ /* Gestures */ +/* NOTE: these values are saved in keymap files, do not change them but just add new ones */ enum { /* value of tweaks and line gestures, note, KM_ANY (-1) works for this case too */ EVT_GESTURE_N = 1, @@ -382,11 +409,10 @@ enum { /* File select */ enum { - EVT_FILESELECT_OPEN = 1, - EVT_FILESELECT_FULL_OPEN = 2, - EVT_FILESELECT_EXEC = 3, - EVT_FILESELECT_CANCEL = 4, - EVT_FILESELECT_EXTERNAL_CANCEL = 5, + EVT_FILESELECT_FULL_OPEN = 1, + EVT_FILESELECT_EXEC = 2, + EVT_FILESELECT_CANCEL = 3, + EVT_FILESELECT_EXTERNAL_CANCEL = 4, }; /* Gesture */ diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 9c9c79d2f54..833234b0f13 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -69,6 +69,11 @@ wmWindow *wm_window_copy (bContext *C, wmWindow *winorig); void wm_window_testbreak (void); +#ifdef WITH_INPUT_IME +void wm_window_IME_begin (wmWindow *win, int x, int y, int w, int h, bool complete); +void wm_window_IME_end (wmWindow *win); +#endif + /* *************** window operators ************** */ int wm_window_duplicate_exec(bContext *C, struct wmOperator *op); int wm_window_fullscreen_toggle_exec(bContext *C, struct wmOperator *op); |