From e22b5fb27130d6408b5ecb3370ca71a5995d3af4 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 7 Oct 2009 05:13:31 +0000 Subject: [PATCH 001/138] * Add numpad enter as an alternative key to confirm/execute file browser --- source/blender/editors/screen/screen_ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 7f2084d5a76..f8112145016 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3330,6 +3330,7 @@ void ED_keymap_screen(wmWindowManager *wm) /* files */ WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0); + WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0); /* undo */ From 828395744ae9c70d3f69c923cd761aaf2f45abb9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 05:26:13 +0000 Subject: [PATCH 002/138] own warnings added last commit --- source/blender/makesrna/intern/rna_material.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index efcf4de062e..9ad42174413 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -59,6 +59,7 @@ static EnumPropertyItem prop_texture_coordinates_items[] = { #include "BKE_depsgraph.h" #include "BKE_main.h" #include "BKE_texture.h" +#include "BKE_node.h" #include "ED_node.h" @@ -176,7 +177,7 @@ static void rna_Material_active_node_material_set(PointerRNA *ptr, PointerRNA va Material *ma= (Material*)ptr->data; Material *ma_act= value.data; - nodeSetActiveID(ma->nodetree, ID_MA, ma_act); + nodeSetActiveID(ma->nodetree, ID_MA, &ma_act->id); } static void rna_MaterialStrand_start_size_range(PointerRNA *ptr, float *min, float *max) From 77476b294f8a7a74ee6f19ff8bfcbb3fb26e3bda Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 07:11:10 +0000 Subject: [PATCH 003/138] Experimental option to allow moving the mouse outside the view, "Continuous Grab" in the user-prefs. - Useful for dragging buttons to the far right when theyd otherwise hit the screen edge. - Useful for transform though probably NOT what you want when using the transform manipulator (should make an option). - When enabled, number buttons use this as well as a different conversion of mouse movement float numbuts: mouse 1px == 1-clickstep int numbuts: 2px == 1 (tried 1:1 but its too jitter prone) details... - access as an option to GHOST_SetCursorGrab(grab, warp) - Currently all operators that grab use this, could be made an operator flag - only Ghost/X11 supported currently --- intern/ghost/GHOST_C-api.h | 2 +- intern/ghost/GHOST_IWindow.h | 2 +- intern/ghost/intern/GHOST_C-api.cpp | 4 +- intern/ghost/intern/GHOST_SystemX11.cpp | 48 ++++- intern/ghost/intern/GHOST_Window.cpp | 12 +- intern/ghost/intern/GHOST_Window.h | 53 ++++- intern/ghost/intern/GHOST_WindowX11.cpp | 23 ++- intern/ghost/intern/GHOST_WindowX11.h | 3 +- release/scripts/ui/space_userpref.py | 4 +- .../editors/interface/interface_handlers.c | 189 ++++++++++++------ source/blender/makesdna/DNA_userdef_types.h | 1 + source/blender/makesrna/intern/rna_userdef.c | 4 + source/blender/windowmanager/WM_api.h | 2 +- .../blender/windowmanager/intern/wm_cursors.c | 4 +- .../windowmanager/intern/wm_event_system.c | 6 +- 15 files changed, 268 insertions(+), 89 deletions(-) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 9460fb504a9..35391d3f4cf 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -376,7 +376,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, * @return Indication of success. */ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, - int grab); + int grab, int warp); /*************************************************************************************** ** Access to mouse button and keyboard states. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index ff1484909b0..44ddf9a7cfb 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -271,7 +271,7 @@ public: * @param grab The new grab state of the cursor. * @return Indication of success. */ - virtual GHOST_TSuccess setCursorGrab(bool grab) { return GHOST_kSuccess; }; + virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp) { return GHOST_kSuccess; }; }; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index d14945d1bf8..b86c4703ea2 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -355,11 +355,11 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, - int grab) + int grab, int warp) { GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; - return window->setCursorGrab(grab?true:false); + return window->setCursorGrab(grab?true:false, warp?true:false); } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index cdbdce9c2ca..8c87abf16bc 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -374,12 +374,12 @@ GHOST_SystemX11::processEvent(XEvent *xe) // Only generate a single expose event // per read of the event queue. - g_event = new + g_event = new GHOST_Event( getMilliSeconds(), GHOST_kEventWindowUpdate, window - ); + ); } break; } @@ -388,14 +388,42 @@ GHOST_SystemX11::processEvent(XEvent *xe) { XMotionEvent &xme = xe->xmotion; - g_event = new - GHOST_EventCursor( - getMilliSeconds(), - GHOST_kEventCursorMove, - window, - xme.x_root, - xme.y_root - ); + if(window->getCursorWarp()) { + /* Calculate offscreen location and re-center the mouse */ + GHOST_TInt32 x_warp, y_warp, x_new, y_new, x_accum, y_accum; + + window->getCursorWarpPos(x_warp, y_warp); + getCursorPosition(x_new, y_new); + + if(x_warp != x_new || y_warp != y_new) { + window->getCursorWarpAccum(x_accum, y_accum); + x_accum += x_new - x_warp; + y_accum += y_new - y_warp; + + window->setCursorWarpAccum(x_accum, y_accum); + setCursorPosition(x_warp, y_warp); /* reset */ + + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + x_warp + x_accum, + y_warp + y_accum + ); + + } + } + else { + g_event = new + GHOST_EventCursor( + getMilliSeconds(), + GHOST_kEventCursorMove, + window, + xme.x_root, + xme.y_root + ); + } break; } diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 34e9f519a07..531674607d1 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -48,12 +48,16 @@ GHOST_Window::GHOST_Window( : m_drawingContextType(type), m_cursorVisible(true), - m_cursorGrabbed(true), + m_cursorGrabbed(false), + m_cursorWarp(false), m_cursorShape(GHOST_kStandardCursorDefault), m_stereoVisual(stereoVisual) { m_isUnsavedChanges = false; + m_cursorWarpAccumPos[0] = 0; + m_cursorWarpAccumPos[1] = 0; + m_fullScreen = state == GHOST_kWindowStateFullScreen; if (m_fullScreen) { m_fullScreenWidth = width; @@ -94,12 +98,12 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) } } -GHOST_TSuccess GHOST_Window::setCursorGrab(bool grab) +GHOST_TSuccess GHOST_Window::setCursorGrab(bool grab, bool warp) { if(m_cursorGrabbed == grab) return GHOST_kSuccess; - if (setWindowCursorGrab(grab)) { + if (setWindowCursorGrab(grab, warp)) { m_cursorGrabbed = grab; return GHOST_kSuccess; } @@ -150,4 +154,4 @@ GHOST_TSuccess GHOST_Window::setModifiedState(bool isUnsavedChanges) bool GHOST_Window::getModifiedState() { return m_isUnsavedChanges; -} \ No newline at end of file +} diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index a2d1675f6ab..36e4bac6dae 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -158,6 +158,10 @@ public: * @return The visibility state of the cursor. */ inline virtual bool getCursorVisibility() const; + inline virtual bool getCursorWarp() const; + inline virtual bool getCursorWarpPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const; + inline virtual bool getCursorWarpAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const; + inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y); /** * Shows or hides the cursor. @@ -171,7 +175,7 @@ public: * @param grab The new grab state of the cursor. * @return Indication of success. */ - virtual GHOST_TSuccess setCursorGrab(bool grab); + virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp); /** * Sets the window "modified" status, indicating unsaved changes @@ -243,7 +247,7 @@ protected: * Sets the cursor grab on the window using * native window system calls. */ - virtual GHOST_TSuccess setWindowCursorGrab(bool grab) { return GHOST_kSuccess; }; + virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp) { return GHOST_kSuccess; }; /** * Sets the cursor shape on the window using @@ -272,6 +276,15 @@ protected: /** The current grabbed state of the cursor */ bool m_cursorGrabbed; + /** The current warped state of the cursor */ + bool m_cursorWarp; + + /** Initial grab location. */ + GHOST_TInt32 m_cursorWarpInitPos[2]; + + /** Accumulated offset from m_cursorWarpInitPos. */ + GHOST_TInt32 m_cursorWarpAccumPos[2]; + /** The current shape of the cursor */ GHOST_TStandardCursor m_cursorShape; @@ -304,6 +317,42 @@ inline bool GHOST_Window::getCursorVisibility() const return m_cursorVisible; } +inline bool GHOST_Window::getCursorWarp() const +{ + return m_cursorWarp; +} + +inline bool GHOST_Window::getCursorWarpPos(GHOST_TInt32 &x, GHOST_TInt32 &y) const +{ + if(m_cursorWarp==false) + return GHOST_kFailure; + + x= m_cursorWarpInitPos[0]; + y= m_cursorWarpInitPos[1]; + return GHOST_kSuccess; +} + +inline bool GHOST_Window::getCursorWarpAccum(GHOST_TInt32 &x, GHOST_TInt32 &y) const +{ + if(m_cursorWarp==false) + return GHOST_kFailure; + + x= m_cursorWarpAccumPos[0]; + y= m_cursorWarpAccumPos[1]; + return GHOST_kSuccess; +} + +inline bool GHOST_Window::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y) +{ + if(m_cursorWarp==false) + return GHOST_kFailure; + + m_cursorWarpAccumPos[0]= x; + m_cursorWarpAccumPos[1]= y; + + return GHOST_kSuccess; +} + inline GHOST_TStandardCursor GHOST_Window::getCursorShape() const { return m_cursorShape; diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 060e9ca6f6c..c2dc1048ea0 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -1400,12 +1400,29 @@ setWindowCursorVisibility( GHOST_TSuccess GHOST_WindowX11:: setWindowCursorGrab( - bool grab + bool grab, bool warp ){ - if(grab) + if(grab) { + if(warp) { + m_system->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + + setCursorWarpAccum(0, 0); + setWindowCursorVisibility(false); + m_cursorWarp= true; + } XGrabPointer(m_display, m_window, True, ButtonPressMask| ButtonReleaseMask|PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); - else + } + else { + if(m_cursorWarp) { /* are we exiting warp */ + setWindowCursorVisibility(true); + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + m_system->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + + setCursorWarpAccum(0, 0); + m_cursorWarp= false; + } XUngrabPointer(m_display, CurrentTime); + } XFlush(m_display); diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 6f8940bdcbb..08fba3e2be8 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -252,10 +252,11 @@ protected: /** * Sets the cursor grab on the window using * native window system calls. + * @param warp Only used when grab is enabled, hides the mouse and allows gragging outside the screen. */ GHOST_TSuccess setWindowCursorGrab( - bool grab + bool grab, bool warp ); /** diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index 15e6c7ee4be..ce8d03d3292 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -109,8 +109,8 @@ class USERPREF_PT_view(bpy.types.Panel): sub1.itemL(text="Mouse Wheel:") sub1.itemR(view, "wheel_invert_zoom", text="Invert Zoom") sub1.itemR(view, "wheel_scroll_lines", text="Scroll Lines") - sub1.itemS() - sub1.itemS() + sub1.itemL(text="Mouse Motion:") + sub1.itemR(view, "continuous_mouse", text="Continuous Grab") sub1.itemS() sub1.itemL(text="Menus:") sub1.itemR(view, "open_mouse_over") diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index bbf8df00b88..385a0eec040 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -230,6 +230,15 @@ static uiBut *ui_but_last(uiBlock *block) return NULL; } +static int ui_is_a_warp_but(uiBut *but) +{ + if(U.uiflag & USER_CONTINUOUS_MOUSE) + if(ELEM(but->type, NUM, NUMABS)) + return TRUE; + + return FALSE; +} + /* ********************** button apply/revert ************************/ static ListBase UIAfterFuncs = {NULL, NULL}; @@ -1971,6 +1980,51 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, wmE return WM_UI_HANDLER_CONTINUE; } +/* var names match ui_numedit_but_NUM */ +static float ui_numedit_apply_snapf(float tempf, float softmin, float softmax, float softrange, int snap) +{ + if(tempf==softmin || tempf==softmax) + return tempf; + + switch(snap) { + case 0: + break; + case 1: + if(tempf==softmin || tempf==softmax) { } + else if(softrange < 2.10) tempf= 0.1*floor(10*tempf); + else if(softrange < 21.0) tempf= floor(tempf); + else tempf= 10.0*floor(tempf/10.0); + break; + case 2: + if(tempf==softmin || tempf==softmax) { } + else if(softrange < 2.10) tempf= 0.01*floor(100.0*tempf); + else if(softrange < 21.0) tempf= 0.1*floor(10.0*tempf); + else tempf= floor(tempf); + break; + } + + return tempf; +} + +static float ui_numedit_apply_snap(int temp, float softmin, float softmax, int snap) +{ + if(temp==softmin || temp==softmax) + return temp; + + switch(snap) { + case 0: + break; + case 1: + temp= 10*(temp/10); + break; + case 2: + temp= 100*(temp/100); + break; + } + + return temp; +} + static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, int snap, int mx) { float deler, tempf, softmin, softmax, softrange; @@ -1993,74 +2047,88 @@ static int ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data, float fac, i softmax= but->softmax; softrange= softmax - softmin; - deler= 500; - if(!ui_is_but_float(but)) { - if((softrange)<100) deler= 200.0; - if((softrange)<25) deler= 50.0; - } - deler /= fac; - if(ui_is_but_float(but) && softrange > 11) { - /* non linear change in mouse input- good for high precicsion */ - data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.002); - } else if (!ui_is_but_float(but) && softrange > 129) { /* only scale large int buttons */ - /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */ - data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.004); - } else { - /*no scaling */ - data->dragf+= ((float)(mx-data->draglastx))/deler ; - } + if(ui_is_a_warp_but(but)) { + /* Mouse location isn't screen clamped to the screen so use a linear mapping + * 2px == 1-int, or 1px == 1-ClickStep */ + if(ui_is_but_float(but)) { + tempf = data->startvalue + ((mx - data->dragstartx) * fac * 0.01*but->a1); + tempf= ui_numedit_apply_snapf(tempf, softmin, softmax, softrange, snap); + CLAMP(tempf, softmin, softmax); - if(data->dragf>1.0) data->dragf= 1.0; - if(data->dragf<0.0) data->dragf= 0.0; - data->draglastx= mx; - tempf= (softmin + data->dragf*softrange); - - if(!ui_is_but_float(but)) { - temp= floor(tempf+.5); - - if(tempf==softmin || tempf==softmax); - else if(snap) { - if(snap == 2) temp= 100*(temp/100); - else temp= 10*(temp/10); + if(tempf != data->value) { + data->dragchange= 1; + data->value= tempf; + changed= 1; + } } + else { + temp= data->startvalue + (mx - data->dragstartx)/2; /* simple 2px == 1 */ + temp= ui_numedit_apply_snap(temp, softmin, softmax, snap); + CLAMP(temp, softmin, softmax); - CLAMP(temp, softmin, softmax); - lvalue= (int)data->value; - - if(temp != lvalue) { - data->dragchange= 1; - data->value= (double)temp; - changed= 1; + if(temp != data->value) { + data->dragchange= 1; + data->value= temp; + changed= 1; + } } } else { - temp= 0; + /* Use a non-linear mapping of the mouse drag especially for large floats (normal behavior) */ + deler= 500; + if(!ui_is_but_float(but)) { + if((softrange)<100) deler= 200.0; + if((softrange)<25) deler= 50.0; + } + deler /= fac; - if(snap) { - if(snap == 2) { - if(tempf==softmin || tempf==softmax); - else if(softrange < 2.10) tempf= 0.01*floor(100.0*tempf); - else if(softrange < 21.0) tempf= 0.1*floor(10.0*tempf); - else tempf= floor(tempf); - } - else { - if(tempf==softmin || tempf==softmax); - else if(softrange < 2.10) tempf= 0.1*floor(10*tempf); - else if(softrange < 21.0) tempf= floor(tempf); - else tempf= 10.0*floor(tempf/10.0); + if(ui_is_but_float(but) && softrange > 11) { + /* non linear change in mouse input- good for high precicsion */ + data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.002); + } else if (!ui_is_but_float(but) && softrange > 129) { /* only scale large int buttons */ + /* non linear change in mouse input- good for high precicsionm ints need less fine tuning */ + data->dragf+= (((float)(mx-data->draglastx))/deler) * (fabs(data->dragstartx-mx)*0.004); + } else { + /*no scaling */ + data->dragf+= ((float)(mx-data->draglastx))/deler ; + } + + if(data->dragf>1.0) data->dragf= 1.0; + if(data->dragf<0.0) data->dragf= 0.0; + data->draglastx= mx; + tempf= (softmin + data->dragf*softrange); + + + if(!ui_is_but_float(but)) { + temp= floor(tempf+.5); + + temp= ui_numedit_apply_snap(temp, softmin, softmax, snap); + + CLAMP(temp, softmin, softmax); + lvalue= (int)data->value; + + if(temp != lvalue) { + data->dragchange= 1; + data->value= (double)temp; + changed= 1; } } + else { + temp= 0; + tempf= ui_numedit_apply_snapf(tempf, softmin, softmax, softrange, snap); - CLAMP(tempf, softmin, softmax); + CLAMP(tempf, softmin, softmax); - if(tempf != data->value) { - data->dragchange= 1; - data->value= tempf; - changed= 1; + if(tempf != data->value) { + data->dragchange= 1; + data->value= tempf; + changed= 1; + } } } + return changed; } @@ -2071,7 +2139,10 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton mx= event->x; my= event->y; - ui_window_to_block(data->region, block, &mx, &my); + + if(!ui_is_a_warp_but(but)) { + ui_window_to_block(data->region, block, &mx, &my); + } if(data->state == BUTTON_STATE_HIGHLIGHT) { /* XXX hardcoded keymap check.... */ @@ -3636,11 +3707,15 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s ui_textedit_end(C, but, data); /* number editing */ - if(state == BUTTON_STATE_NUM_EDITING) + if(state == BUTTON_STATE_NUM_EDITING) { + if(ui_is_a_warp_but(but)) + WM_cursor_grab(CTX_wm_window(C), 1, 1); ui_numedit_begin(but, data); - else if(data->state == BUTTON_STATE_NUM_EDITING) + } else if(data->state == BUTTON_STATE_NUM_EDITING) { ui_numedit_end(but, data); - + if(ui_is_a_warp_but(but)) + WM_cursor_grab(CTX_wm_window(C), 0, -1); + } /* menu open */ if(state == BUTTON_STATE_MENU_OPEN) ui_blockopen_begin(C, but, data); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 16ab3e1e9bd..edfc4999d80 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -402,6 +402,7 @@ extern UserDef U; /* from blenkernel blender.c */ #define USER_SHOW_FPS (1 << 21) #define USER_MMB_PASTE (1 << 22) #define USER_MENUFIXEDORDER (1 << 23) +#define USER_CONTINUOUS_MOUSE (1 << 24) /* Auto-Keying mode */ /* AUTOKEY_ON is a bitflag */ diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 25448d0c2de..1c6bd6515ff 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1655,6 +1655,10 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_boolean_negative_sdna(prop, NULL, "uiflag", USER_MENUFIXEDORDER); RNA_def_property_ui_text(prop, "Contents Follow Opening Direction", "Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction."); + prop= RNA_def_property(srna, "continuous_mouse", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_CONTINUOUS_MOUSE); + RNA_def_property_ui_text(prop, "Contents Follow Opening Direction", "Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction."); + prop= RNA_def_property(srna, "global_pivot", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCKAROUND); RNA_def_property_ui_text(prop, "Global Pivot", "Lock the same rotation/scaling pivot in all 3D Views."); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 489f27990cd..321afec51b7 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -75,7 +75,7 @@ void WM_cursor_set (struct wmWindow *win, int curs); void WM_cursor_modal (struct wmWindow *win, int curs); void WM_cursor_restore (struct wmWindow *win); void WM_cursor_wait (int val); -void WM_cursor_grab (struct wmWindow *win, int val); +void WM_cursor_grab (struct wmWindow *win, int val, int warp); void WM_timecursor (struct wmWindow *win, int nr); void *WM_paint_cursor_activate(struct wmWindowManager *wm, int (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata); diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index 56a8d76d8bf..d14cde56083 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -163,10 +163,10 @@ void WM_cursor_wait(int val) } } -void WM_cursor_grab(wmWindow *win, int val) +void WM_cursor_grab(wmWindow *win, int val, int warp) { if(win) - GHOST_SetCursorGrab(win->ghostwin, val); + GHOST_SetCursorGrab(win->ghostwin, val, warp); } /* afer this you can call restore too */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index c15106e21c9..54841f0e063 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -442,7 +442,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P else if(retval & OPERATOR_RUNNING_MODAL) { /* grab cursor during blocking modal ops (X11) */ if(ot->flag & OPTYPE_BLOCKING) - WM_cursor_grab(CTX_wm_window(C), 1); + WM_cursor_grab(CTX_wm_window(C), 1, (U.uiflag & USER_CONTINUOUS_MOUSE)); } else WM_operator_free(op); @@ -637,8 +637,8 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) CTX_wm_region_set(C, region); } + WM_cursor_grab(CTX_wm_window(C), 0, -1); WM_operator_free(handler->op); - WM_cursor_grab(CTX_wm_window(C), 0); } else if(handler->ui_remove) { ScrArea *area= CTX_wm_area(C); @@ -835,7 +835,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand /* remove modal handler, operator itself should have been cancelled and freed */ if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_cursor_grab(CTX_wm_window(C), 0); + WM_cursor_grab(CTX_wm_window(C), 0, -1); BLI_remlink(handlers, handler); wm_event_free_handler(handler); From dfe7cde9f1a8dc90d6d77e2c1108bcb0e87eef82 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 09:23:29 +0000 Subject: [PATCH 004/138] - rna path lookup crashed if the string was null (reported by Cessen with an empty driver) - added TexMesh access ([#19505] Missing option : TexMesh) - Ctrl+Tab works again, not-so-nice workaround, disallow switching to paint modes from editmode, but would be nicer to manage this with keymaps. --- release/scripts/ui/buttons_data_mesh.py | 14 ++++++++++++++ source/blender/editors/mesh/editmesh_mods.c | 8 +++++--- source/blender/editors/object/object_edit.c | 6 ++++++ source/blender/makesrna/intern/rna_access.c | 3 +++ source/blender/makesrna/intern/rna_mesh.c | 7 ++++++- source/blender/makesrna/intern/rna_scene.c | 2 ++ 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/release/scripts/ui/buttons_data_mesh.py b/release/scripts/ui/buttons_data_mesh.py index 780ae3ac8f9..055cbb02e3f 100644 --- a/release/scripts/ui/buttons_data_mesh.py +++ b/release/scripts/ui/buttons_data_mesh.py @@ -48,6 +48,19 @@ class DATA_PT_normals(DataButtonsPanel): col.itemR(mesh, "vertex_normal_flip") col.itemR(mesh, "double_sided") +class DATA_PT_settings(DataButtonsPanel): + __label__ = "Settings" + + def draw(self, context): + layout = self.layout + + mesh = context.mesh + + split = layout.split() + + col = split.column() + col.itemR(mesh, "texture_mesh") + class DATA_PT_vertex_groups(DataButtonsPanel): __label__ = "Vertex Groups" @@ -197,6 +210,7 @@ class DATA_PT_vertex_colors(DataButtonsPanel): bpy.types.register(DATA_PT_context_mesh) bpy.types.register(DATA_PT_normals) +bpy.types.register(DATA_PT_settings) bpy.types.register(DATA_PT_vertex_groups) bpy.types.register(DATA_PT_shape_keys) bpy.types.register(DATA_PT_uv_texture) diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 325a1aeec99..a23a6dde652 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -78,6 +78,8 @@ editmesh_mods.c, UI level access, no geometry changes #include "WM_api.h" #include "WM_types.h" +#include "UI_resources.h" + #include "RNA_access.h" #include "RNA_define.h" @@ -3614,9 +3616,9 @@ static void mesh_selection_type(ToolSettings *ts, EditMesh *em, int val) } static EnumPropertyItem prop_mesh_edit_types[] = { - {1, "VERT", 0, "Vertices", ""}, - {2, "EDGE", 0, "Edges", ""}, - {3, "FACE", 0, "Faces", ""}, + {1, "VERT", ICON_VERTEXSEL, "Vertices", ""}, + {2, "EDGE", ICON_EDGESEL, "Edges", ""}, + {3, "FACE", ICON_FACESEL, "Faces", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 54df3ae92da..268cd3b3542 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1995,6 +1995,12 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) if(!ob || !object_mode_set_compat(C, op, ob)) return OPERATOR_PASS_THROUGH; + /* Irritating workaround! disallow paint modes from editmode since a number of shortcuts conflict + * XXX - would be much better to handle this on a keymap level */ + if(ob->mode == OB_MODE_EDIT && ELEM6(mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT, OB_MODE_PARTICLE_EDIT, OB_MODE_POSE)) { + return OPERATOR_PASS_THROUGH; + } + /* Exit current mode if it's not the mode we're setting */ if(ob->mode != OB_MODE_OBJECT && ob->mode != mode) WM_operator_name_call(C, object_mode_op_string(ob->mode), WM_OP_EXEC_REGION_WIN, NULL); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 21fbc9fa66d..780a387ddbb 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2226,6 +2226,9 @@ int RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prope prop= NULL; curptr= *ptr; + if(path) + return 0; + while(*path) { /* look up property name in current struct */ token= rna_path_token(&path, fixedbuf, sizeof(fixedbuf), 0); diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 124fd80ce5a..84a1940de9d 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1413,8 +1413,13 @@ static void rna_def_mesh(BlenderRNA *brna) RNA_def_property_struct_type(prop, "MeshSticky"); RNA_def_property_ui_text(prop, "Sticky", "Sticky texture coordinates."); - /* UV textures */ + /* TODO, should this be allowed to be its self? */ + prop= RNA_def_property(srna, "texture_mesh", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "texcomesh"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Texture Mesh", "Use another mesh for texture indicies (vertex indicies must be aligned)."); + /* UV textures */ prop= RNA_def_property(srna, "uv_textures", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "fdata.layers", "fdata.totlayer"); RNA_def_property_collection_funcs(prop, "rna_Mesh_uv_textures_begin", 0, 0, 0, "rna_Mesh_uv_textures_length", 0, 0, 0, 0); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 9eea920e371..c771259d5a1 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -279,6 +279,7 @@ void rna_SceneRenderData_jpeg2k_preset_update(RenderData *rd) } } +#ifdef WITH_OPENJPEG static void rna_SceneRenderData_jpeg2k_preset_set(PointerRNA *ptr, int value) { RenderData *rd= (RenderData*)ptr->data; @@ -292,6 +293,7 @@ static void rna_SceneRenderData_jpeg2k_depth_set(PointerRNA *ptr, int value) rd->jp2_depth= value; rna_SceneRenderData_jpeg2k_preset_update(rd); } +#endif static int rna_SceneRenderData_active_layer_index_get(PointerRNA *ptr) { From 60e75845fbae77e70cac0509b5ee6b19835aa920 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Wed, 7 Oct 2009 09:49:37 +0000 Subject: [PATCH 005/138] Fix compile warning, function does not return anything (void function). --- source/blender/editors/interface/view2d.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f7546e94f86..0bd0435362f 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -700,7 +700,7 @@ void UI_view2d_curRect_validate_resize(View2D *v2d, int resize) void UI_view2d_curRect_validate(View2D *v2d) { - return UI_view2d_curRect_validate_resize(v2d, 0); + UI_view2d_curRect_validate_resize(v2d, 0); } /* ------------------ */ From 395e61e77cb94fa67a15684b45bb537fb6046ab7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 09:55:18 +0000 Subject: [PATCH 006/138] own mistake in last commit --- source/blender/makesrna/intern/rna_access.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 780a387ddbb..da467381c06 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2226,7 +2226,7 @@ int RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prope prop= NULL; curptr= *ptr; - if(path) + if(path==NULL) return 0; while(*path) { From efe38580007526ff210dbf5fbeb0815ff081dc65 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 7 Oct 2009 10:54:43 +0000 Subject: [PATCH 007/138] Bugfix: move to layer was not assigned to M key yet. --- source/blender/editors/object/object_ops.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 9bfd6a4201c..91e21e77f3a 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -241,6 +241,8 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_add_item(keymap, "OBJECT_OT_restrictview_clear", HKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_restrictview_set", HKEY, KM_PRESS, 0, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_restrictview_set", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1); + + WM_keymap_add_item(keymap, "OBJECT_OT_move_to_layer", MKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0); From a899e9dd18a988e711194b50dd670dc180e3ba28 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 11:36:29 +0000 Subject: [PATCH 008/138] Check if the object is in editmode with (ob->mode==OB_MODE_EDIT) rather then (ob==scene->obedit) Was trying to fix a hard to redo crash with custom bone shapes in editmode but cant redo. still, will help with future multi-editmode. --- source/blender/blenkernel/intern/anim.c | 4 ++-- source/blender/blenkernel/intern/modifier.c | 2 +- source/blender/blenkernel/intern/object.c | 2 +- source/blender/editors/space_view3d/drawmesh.c | 6 +++--- source/blender/editors/space_view3d/drawobject.c | 10 +++++----- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 5cd901066f8..bb7a792943e 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -549,7 +549,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl /* mballs have a different dupli handling */ if(ob->type!=OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ - if(par==scene->obedit) { + if(par->mode==OB_MODE_EDIT) { dm->foreachMappedVert(dm, vertex_dupli__mapFunc, (void*) &vdd); } else { @@ -760,7 +760,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa else go= go->next; /* group loop */ } - if(par==scene->obedit) { + if(par->mode==OB_MODE_EDIT) { MEM_freeN(mface); MEM_freeN(mvert); } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 55fb9f45bb3..f36713dd8a9 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -9137,7 +9137,7 @@ int modifiers_isDeformed(Scene *scene, Object *ob) ModifierData *md = modifiers_getVirtualModifierList(ob); for (; md; md=md->next) { - if(ob==scene->obedit && (md->mode & eModifierMode_Editmode)==0); + if(ob->mode==OB_MODE_EDIT && (md->mode & eModifierMode_Editmode)==0); else if(modifier_isDeformer(md)) return 1; diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 579466ea626..ddf7e7ff4a3 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2367,7 +2367,7 @@ void object_handle_update(Scene *scene, Object *ob) EditMesh *em = BKE_mesh_get_editmesh(ob->data); // here was vieweditdatamask? XXX - if(ob==scene->obedit) { + if(ob->mode==OB_MODE_EDIT) { makeDerivedMesh(scene, ob, em, CD_MASK_BAREMESH); BKE_mesh_end_editmesh(ob->data, em); } else diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index a4d7ae802f6..dbe0844cbe5 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -350,7 +350,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O int istex, solidtex= 0; // XXX scene->obedit warning - if(v3d->drawtype==OB_SOLID || (ob==scene->obedit && v3d->drawtype!=OB_TEXTURE)) { + if(v3d->drawtype==OB_SOLID || (ob->mode==OB_MODE_EDIT && v3d->drawtype!=OB_TEXTURE)) { /* draw with default lights in solid draw mode and edit mode */ solidtex= 1; Gtexdraw.islit= -1; @@ -561,7 +561,7 @@ void draw_mesh_text(Scene *scene, Object *ob, int glsl) return; /* don't draw when editing */ - if(ob == scene->obedit) + if(ob->mode==OB_MODE_EDIT) return; else if(ob==OBACT) if(paint_facesel_test(ob)) @@ -641,7 +641,7 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *o /* draw the textured mesh */ draw_textured_begin(scene, v3d, rv3d, ob); - if(ob == scene->obedit) { + if(ob->mode==OB_MODE_EDIT) { glColor4f(1.0f,1.0f,1.0f,1.0f); dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh); } else if(faceselect) { diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 1bad1b3215c..2d998c5ed5e 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -5512,7 +5512,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) if(ob==OBACT && (ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT))) { if(ob->type==OB_MESH) { - if(ob==scene->obedit); + if(ob->mode==OB_MODE_EDIT); else { if(dt=OB_BOUNDBOX ) { dtx= ob->dtx; - if(scene->obedit==ob) { + if(ob->mode==OB_MODE_EDIT) { // the only 2 extra drawtypes alowed in editmode dtx= dtx & (OB_DRAWWIRE|OB_TEXSPACE); } @@ -5550,7 +5550,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int flag) /* draw outline for selected solid objects, mesh does itself */ if((v3d->flag & V3D_SELECT_OUTLINE) && ob->type!=OB_MESH) { - if(dt>OB_WIRE && dtobedit && (flag && DRAW_SCENESET)==0) { + if(dt>OB_WIRE && dtmode!=OB_MODE_EDIT && (flag && DRAW_SCENESET)==0) { if (!(ob->dtx&OB_DRAWWIRE) && (ob->flag&SELECT) && !(flag&DRAW_PICKING)) { drawSolidSelect(scene, v3d, ar, base); @@ -6159,7 +6159,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec switch( ob->type) { case OB_MESH: { - if(ob == scene->obedit) { + if(ob->mode==OB_MODE_EDIT) { Mesh *me= ob->data; EditMesh *em= me->edit_mesh; @@ -6215,7 +6215,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r DerivedMesh *dm=NULL, *edm=NULL; int glsl; - if(ob == scene->obedit) + if(ob->mode == OB_MODE_EDIT) edm= editmesh_get_derived_base(ob, me->edit_mesh); else dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH); From f5a9f420fb1862497bee790c0d9ace5afeb09de9 Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Wed, 7 Oct 2009 12:17:29 +0000 Subject: [PATCH 009/138] * More fixes post-raytrace commit --- .../render/intern/source/volume_precache.c | 71 ++++--------------- .../blender/render/intern/source/volumetric.c | 11 +-- 2 files changed, 15 insertions(+), 67 deletions(-) diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c index 01930956763..3361eea46e7 100644 --- a/source/blender/render/intern/source/volume_precache.c +++ b/source/blender/render/intern/source/volume_precache.c @@ -74,11 +74,15 @@ int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int l if (RE_rayobject_raycast(tree, isect)) { float hitco[3]; - hitco[0] = isect->start[0] + isect->labda*isect->vec[0]; - hitco[1] = isect->start[1] + isect->labda*isect->vec[1]; - hitco[2] = isect->start[2] + isect->labda*isect->vec[2]; - VecAddf(isect->start, hitco, offset); - + isect->start[0] = isect->start[0] + isect->labda*isect->vec[0]; + isect->start[1] = isect->start[1] + isect->labda*isect->vec[1]; + isect->start[2] = isect->start[2] + isect->labda*isect->vec[2]; + + isect->labda = FLT_MAX; + isect->skip = RE_SKIP_VLR_NEIGHBOUR; + isect->orig.face= isect->hit.face; + isect->orig.ob= isect->hit.ob; + return intersect_outside_volume(tree, isect, offset, limit-1, depth+1); } else { return depth; @@ -96,22 +100,14 @@ int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, float *co) memset(&isect, 0, sizeof(isect)); VECCOPY(isect.start, co); VECCOPY(isect.vec, vec); - isect.labda = FLT_MAX; - - /* - isect.end[0] = co[0] + vec[0] * maxsize; - isect.end[1] = co[1] + vec[1] * maxsize; - isect.end[2] = co[2] + vec[2] * maxsize; - */ - - /* and give it a little offset to prevent self-intersections */ - VecMulf(vec, 1e-5); - VecAddf(isect.start, isect.start, vec); - isect.mode= RE_RAY_MIRROR; isect.last_hit= NULL; isect.lay= -1; + isect.labda = FLT_MAX; + isect.orig.face= NULL; + isect.orig.ob = NULL; + final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth); /* even number of intersections: point is outside @@ -120,47 +116,6 @@ int point_inside_obi(RayObject *tree, ObjectInstanceRen *obi, float *co) else return 1; } -/* -static int inside_check_func(Isect *is, int ob, RayObject *face) -{ - return 1; -} - -static void vlr_face_coords(RayFace *face, float **v1, float **v2, float **v3, float **v4) -{ - VlakRen *vlr= (VlakRen*)face; - - *v1 = (vlr->v1)? vlr->v1->co: NULL; - *v2 = (vlr->v2)? vlr->v2->co: NULL; - *v3 = (vlr->v3)? vlr->v3->co: NULL; - *v4 = (vlr->v4)? vlr->v4->co: NULL; -} - -RayObject *create_raytree_obi(ObjectInstanceRen *obi, float *bbmin, float *bbmax) -{ - int v; - VlakRen *vlr= NULL; - - / * create empty raytree * / - RayTree *tree = RE_ray_tree_create(64, obi->obr->totvlak, bbmin, bbmax, - vlr_face_coords, inside_check_func, NULL, NULL); - - / * fill it with faces * / - for(v=0; vobr->totvlak; v++) { - if((v & 255)==0) - vlr= obi->obr->vlaknodes[v>>8].vlak; - else - vlr++; - - RE_ray_tree_add_face(tree, 0, vlr); - } - - RE_ray_tree_done(tree); - - return tree; -} -*/ - /* *** light cache filtering *** */ static float get_avg_surrounds(float *cache, int *res, int xx, int yy, int zz) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index 90ac45edb60..fd7ffc8c845 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -98,15 +98,14 @@ static float vol_get_shadow(ShadeInput *shi, LampRen *lar, float *co) } is.mode = RE_RAY_MIRROR; - is.skip = RE_SKIP_VLR_NEIGHBOUR | RE_SKIP_VLR_RENDER_CHECK | RE_SKIP_VLR_NON_SOLID_MATERIAL; + is.skip = RE_SKIP_VLR_RENDER_CHECK | RE_SKIP_VLR_NON_SOLID_MATERIAL; if(lar->mode & (LA_LAYER|LA_LAYER_SHADOW)) is.lay= lar->lay; else is.lay= -1; - is.last_hit = NULL; - is.orig.ob = (void*)shi->obi; + is.orig.ob = NULL; is.orig.face = NULL; is.last_hit = lar->last_hit[shi->thread]; @@ -132,12 +131,6 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, VECCOPY(isect->start, co); VECCOPY(isect->vec, vec ); isect->labda = FLT_MAX; - /* - isect->end[0] = co[0] + vec[0] * maxsize; - isect->end[1] = co[1] + vec[1] * maxsize; - isect->end[2] = co[2] + vec[2] * maxsize; - */ - isect->mode= RE_RAY_MIRROR; isect->last_hit = NULL; isect->lay= -1; From 9cf78144f1e6369bc640df783b4ec7b5f2a15235 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 12:19:47 +0000 Subject: [PATCH 010/138] Updated descriptions from Ron Walker --- source/blender/editors/screen/screen_ops.c | 28 ++++++++++++++++++- .../editors/space_buttons/buttons_ops.c | 4 +-- source/blender/editors/space_file/file_ops.c | 21 +++++++++++++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f8112145016..ad0218f3b80 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -512,6 +512,7 @@ static void SCREEN_OT_actionzone(wmOperatorType *ot) { /* identifiers */ ot->name= "Handle area action zones"; + ot->description= "Handle area action zones for mouse actions/gestures."; ot->idname= "SCREEN_OT_actionzone"; ot->invoke= actionzone_invoke; @@ -628,6 +629,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event) static void SCREEN_OT_area_swap(wmOperatorType *ot) { ot->name= "Swap areas"; + ot->description= "Swap selected areas screen positions."; ot->idname= "SCREEN_OT_area_swap"; ot->invoke= area_swap_invoke; @@ -692,6 +694,7 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event) static void SCREEN_OT_area_dupli(wmOperatorType *ot) { ot->name= "Duplicate Area into New Window"; + ot->description= "Duplicate selected area into new window."; ot->idname= "SCREEN_OT_area_dupli"; ot->invoke= area_dupli_invoke; @@ -931,6 +934,7 @@ static void SCREEN_OT_area_move(wmOperatorType *ot) { /* identifiers */ ot->name= "Move area edges"; + ot->description= "Move selected area edges."; ot->idname= "SCREEN_OT_area_move"; ot->exec= area_move_exec; @@ -1246,6 +1250,7 @@ static EnumPropertyItem prop_direction_items[] = { static void SCREEN_OT_area_split(wmOperatorType *ot) { ot->name = "Split area"; + ot->description= "Split selected area into new windows."; ot->idname = "SCREEN_OT_area_split"; ot->exec= area_split_exec; @@ -1372,6 +1377,7 @@ static void SCREEN_OT_region_scale(wmOperatorType *ot) { /* identifiers */ ot->name= "Scale Region Size"; + ot->description= "Scale selected area."; ot->idname= "SCREEN_OT_region_scale"; ot->invoke= region_scale_invoke; @@ -1432,6 +1438,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op) static void SCREEN_OT_frame_jump(wmOperatorType *ot) { ot->name = "Jump to Endpoint"; + ot->description= "Jump to first/last frame in frame range."; ot->idname = "SCREEN_OT_frame_jump"; ot->exec= frame_jump_exec; @@ -1497,6 +1504,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) static void SCREEN_OT_keyframe_jump(wmOperatorType *ot) { ot->name = "Jump to Keyframe"; + ot->description= "Jump to previous/next keyframe."; ot->idname = "SCREEN_OT_keyframe_jump"; ot->exec= keyframe_jump_exec; @@ -1553,6 +1561,7 @@ static int screen_set_exec(bContext *C, wmOperator *op) static void SCREEN_OT_screen_set(wmOperatorType *ot) { ot->name = "Set Screen"; + ot->description= "Cycle through available screens."; ot->idname = "SCREEN_OT_screen_set"; ot->exec= screen_set_exec; @@ -1575,6 +1584,7 @@ static int screen_full_area_exec(bContext *C, wmOperator *op) static void SCREEN_OT_screen_full_area(wmOperatorType *ot) { ot->name = "Toggle Full Screen"; + ot->description= "Toggle display selected area as fullscreen."; ot->idname = "SCREEN_OT_screen_full_area"; ot->exec= screen_full_area_exec; @@ -1848,6 +1858,7 @@ static void SCREEN_OT_area_join(wmOperatorType *ot) { /* identifiers */ ot->name= "Join area"; + ot->description= "Join selected areas into new window."; ot->idname= "SCREEN_OT_area_join"; /* api callbacks */ @@ -1881,6 +1892,7 @@ static void SCREEN_OT_repeat_last(wmOperatorType *ot) { /* identifiers */ ot->name= "Repeat Last"; + ot->description= "Repeat last action."; ot->idname= "SCREEN_OT_repeat_last"; /* api callbacks */ @@ -1933,6 +1945,7 @@ static void SCREEN_OT_repeat_history(wmOperatorType *ot) { /* identifiers */ ot->name= "Repeat History"; + ot->description= "Display menu for previous actions performed."; ot->idname= "SCREEN_OT_repeat_history"; /* api callbacks */ @@ -1966,6 +1979,7 @@ static void SCREEN_OT_redo_last(wmOperatorType *ot) { /* identifiers */ ot->name= "Redo Last"; + ot->description= "Display menu for last action performed."; ot->idname= "SCREEN_OT_redo_last"; /* api callbacks */ @@ -2009,6 +2023,7 @@ static void SCREEN_OT_region_split(wmOperatorType *ot) { /* identifiers */ ot->name= "Split Region"; + ot->description= "Split area by directional position."; ot->idname= "SCREEN_OT_region_split"; /* api callbacks */ @@ -2098,6 +2113,7 @@ static void SCREEN_OT_region_foursplit(wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Quad View"; + ot->description= "Split selected area into camera, front, right & top views."; ot->idname= "SCREEN_OT_region_foursplit"; /* api callbacks */ @@ -2292,6 +2308,7 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot) { /* identifiers */ ot->name= "Animation Step"; + ot->description= "Step through animation by position."; ot->idname= "SCREEN_OT_animation_step"; /* api callbacks */ @@ -2348,6 +2365,7 @@ static void SCREEN_OT_animation_play(wmOperatorType *ot) { /* identifiers */ ot->name= "Play Animation"; + ot->description= "Play animation."; ot->idname= "SCREEN_OT_animation_play"; /* api callbacks */ @@ -2945,6 +2963,7 @@ static void SCREEN_OT_render(wmOperatorType *ot) { /* identifiers */ ot->name= "Render"; + ot->description= "Render active scene."; ot->idname= "SCREEN_OT_render"; /* api callbacks */ @@ -2992,6 +3011,7 @@ static void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Cancel Render View"; + ot->description= "Cancel show render view."; ot->idname= "SCREEN_OT_render_view_cancel"; /* api callbacks */ @@ -3037,6 +3057,7 @@ static void SCREEN_OT_render_view_show(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Show/Hide Render View"; + ot->description= "Toggle show render view."; ot->idname= "SCREEN_OT_render_view_show"; /* api callbacks */ @@ -3075,6 +3096,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Show/Hide User Preferences"; + ot->description= "Show/hide user preferences."; ot->idname= "SCREEN_OT_userpref_show"; /* api callbacks */ @@ -3099,6 +3121,7 @@ void SCREEN_OT_new(wmOperatorType *ot) { /* identifiers */ ot->name= "New Screen"; + ot->description= "Add a new screen."; ot->idname= "SCREEN_OT_new"; /* api callbacks */ @@ -3122,7 +3145,8 @@ static int screen_delete_exec(bContext *C, wmOperator *op) void SCREEN_OT_delete(wmOperatorType *ot) { /* identifiers */ - ot->name= "Delete Scene"; + ot->name= "Delete Screen"; //was scene + ot->description= "Delete active screen."; ot->idname= "SCREEN_OT_delete"; /* api callbacks */ @@ -3164,6 +3188,7 @@ void SCENE_OT_new(wmOperatorType *ot) /* identifiers */ ot->name= "New Scene"; + ot->description= "Add new scene by type."; ot->idname= "SCENE_OT_new"; /* api callbacks */ @@ -3192,6 +3217,7 @@ void SCENE_OT_delete(wmOperatorType *ot) { /* identifiers */ ot->name= "Delete Scene"; + ot->description= "Delete active scene."; ot->idname= "SCENE_OT_delete"; /* api callbacks */ diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 2d961f78243..634b3e36ea7 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -70,8 +70,8 @@ void BUTTONS_OT_toolbox(wmOperatorType *ot) { /* identifiers */ ot->name= "Toolbox"; + ot->description="Display button panel toolbox"; ot->idname= "BUTTONS_OT_toolbox"; - ot->description="Toolbar panel? DOC_BROKEN"; /* api callbacks */ ot->invoke= toolbox_invoke; @@ -139,8 +139,8 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot) { /* identifiers */ ot->name= "File Browse"; - ot->idname= "BUTTONS_OT_file_browse"; ot->description="Open a file browser."; + ot->idname= "BUTTONS_OT_file_browse"; /* api callbacks */ ot->invoke= file_browse_invoke; diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 75230813a41..c0be1ffb637 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -221,6 +221,7 @@ void FILE_OT_select_border(wmOperatorType *ot) { /* identifiers */ ot->name= "Activate/Select File"; + ot->description= "Activate/select the file(s) contained in the border."; ot->idname= "FILE_OT_select_border"; /* api callbacks */ @@ -273,6 +274,7 @@ void FILE_OT_select(wmOperatorType *ot) { /* identifiers */ ot->name= "Activate/Select File"; + ot->description= "Activate/select file."; ot->idname= "FILE_OT_select"; /* api callbacks */ @@ -317,6 +319,7 @@ void FILE_OT_select_all_toggle(wmOperatorType *ot) { /* identifiers */ ot->name= "Select/Deselect all files"; + ot->description= "Select/deselect all files."; ot->idname= "FILE_OT_select_all_toggle"; /* api callbacks */ @@ -352,6 +355,7 @@ void FILE_OT_select_bookmark(wmOperatorType *ot) { /* identifiers */ ot->name= "Select Directory"; + ot->description= "Select a bookmarked directory."; ot->idname= "FILE_OT_select_bookmark"; /* api callbacks */ @@ -384,6 +388,7 @@ void FILE_OT_add_bookmark(wmOperatorType *ot) { /* identifiers */ ot->name= "Add Bookmark"; + ot->description= "Add a bookmark for the selected/active directory."; ot->idname= "FILE_OT_add_bookmark"; /* api callbacks */ @@ -416,6 +421,7 @@ void FILE_OT_delete_bookmark(wmOperatorType *ot) { /* identifiers */ ot->name= "Delete Bookmark"; + ot->description= "Delete selected bookmark."; ot->idname= "FILE_OT_delete_bookmark"; /* api callbacks */ @@ -445,6 +451,7 @@ void FILE_OT_loadimages(wmOperatorType *ot) /* identifiers */ ot->name= "Load Images"; + ot->description= "Load selected image(s)."; ot->idname= "FILE_OT_loadimages"; /* api callbacks */ @@ -499,6 +506,7 @@ void FILE_OT_highlight(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Highlight File"; + ot->description= "Highlight selected file(s)."; ot->idname= "FILE_OT_highlight"; /* api callbacks */ @@ -540,6 +548,7 @@ void FILE_OT_cancel(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Cancel File Load"; + ot->description= "Cancel loading of selected file."; ot->idname= "FILE_OT_cancel"; /* api callbacks */ @@ -619,6 +628,7 @@ void FILE_OT_execute(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Execute File Window"; + ot->description= "Execute selected file."; ot->idname= "FILE_OT_execute"; /* api callbacks */ @@ -649,6 +659,7 @@ void FILE_OT_parent(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Parent File"; + ot->description= "Move to parent directory."; ot->idname= "FILE_OT_parent"; /* api callbacks */ @@ -673,6 +684,7 @@ void FILE_OT_previous(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Previous Folder"; + ot->description= "Move to previous folder."; ot->idname= "FILE_OT_previous"; /* api callbacks */ @@ -703,6 +715,7 @@ void FILE_OT_next(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Next Folder"; + ot->description= "Move to next folder."; ot->idname= "FILE_OT_next"; /* api callbacks */ @@ -766,8 +779,8 @@ void FILE_OT_directory_new(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Create New Directory"; - ot->idname= "FILE_OT_directory_new"; ot->description= "Create a new directory"; + ot->idname= "FILE_OT_directory_new"; /* api callbacks */ ot->invoke= WM_operator_confirm; @@ -832,6 +845,7 @@ void FILE_OT_refresh(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Refresh Filelist"; + ot->description= "Refresh the file list."; ot->idname= "FILE_OT_refresh"; /* api callbacks */ @@ -859,6 +873,7 @@ void FILE_OT_hidedot(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Hide Dot Files"; + ot->description= "Toggle hide hidden dot files."; ot->idname= "FILE_OT_hidedot"; /* api callbacks */ @@ -908,6 +923,7 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Toggle Bookmarks"; + ot->description= "Toggle bookmarks display."; ot->idname= "FILE_OT_bookmark_toggle"; /* api callbacks */ @@ -936,6 +952,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Increment Number in Filename"; + ot->description= "Increment number in filename."; ot->idname= "FILE_OT_filenum"; /* api callbacks */ @@ -987,6 +1004,7 @@ void FILE_OT_rename(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Rename File or Directory"; + ot->description= "Rename file or file directory."; ot->idname= "FILE_OT_rename"; /* api callbacks */ @@ -1037,6 +1055,7 @@ void FILE_OT_delete(struct wmOperatorType *ot) { /* identifiers */ ot->name= "Delete File"; + ot->description= "Delete selected file."; ot->idname= "FILE_OT_delete"; /* api callbacks */ From 568be173266d42321909b1b9e047d214775c237c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 13:22:56 +0000 Subject: [PATCH 011/138] Option to copy the data path of an RNA button --- .../blender/editors/animation/anim_intern.h | 2 + source/blender/editors/animation/anim_ops.c | 2 + source/blender/editors/animation/drivers.c | 44 +++++++++++++++++++ .../editors/interface/interface_anim.c | 3 ++ 4 files changed, 51 insertions(+) diff --git a/source/blender/editors/animation/anim_intern.h b/source/blender/editors/animation/anim_intern.h index 853aeb6c8f3..0101e3d0ef7 100644 --- a/source/blender/editors/animation/anim_intern.h +++ b/source/blender/editors/animation/anim_intern.h @@ -79,4 +79,6 @@ void ANIM_OT_remove_driver_button(struct wmOperatorType *ot); void ANIM_OT_copy_driver_button(struct wmOperatorType *ot); void ANIM_OT_paste_driver_button(struct wmOperatorType *ot); +void ANIM_OT_copy_clipboard_button(struct wmOperatorType *ot); + #endif // ANIM_INTERN_H diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 4317204f347..83b2e2688c9 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -404,6 +404,8 @@ void ED_operatortypes_anim(void) WM_operatortype_append(ANIM_OT_copy_driver_button); WM_operatortype_append(ANIM_OT_paste_driver_button); + WM_operatortype_append(ANIM_OT_copy_clipboard_button); + WM_operatortype_append(ANIM_OT_add_keyingset_button); WM_operatortype_append(ANIM_OT_remove_keyingset_button); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 363a5a80f00..7a457548623 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -564,4 +564,48 @@ void ANIM_OT_paste_driver_button (wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } + +/* Paste Driver Button Operator ------------------------ */ + +static int copy_clipboard_button_exec(bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop= NULL; + char *path; + short success= 0; + int index; + + /* try to create driver using property retrieved from UI */ + memset(&ptr, 0, sizeof(PointerRNA)); + uiAnimContextProperty(C, &ptr, &prop, &index); + + if (ptr.data && prop) { // && RNA_property_animateable(ptr.data, prop) + path= RNA_path_from_ID_to_property(&ptr, prop); + + if (path) { + WM_clipboard_text_set(path, FALSE); + MEM_freeN(path); + } + } + + /* since we're just copying, we don't really need to do anything else...*/ + return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; +} + +void ANIM_OT_copy_clipboard_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Data Path"; + ot->idname= "ANIM_OT_copy_clipboard_button"; + ot->description= "Copy the rna data path to the clipboard."; + + /* callbacks */ + ot->exec= copy_clipboard_button_exec; + //op->poll= ??? // TODO: need to have some driver to be able to do this... + + /* flags */ + ot->flag= 0; +} + + /* ************************************************** */ diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 8037a609a2f..facda32a41e 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -310,6 +310,9 @@ void ui_but_anim_menu(bContext *C, uiBut *but) } } + uiItemS(layout); + uiItemBooleanO(layout, "Copy Data Path", 0, "ANIM_OT_copy_clipboard_button", "all", 1); + uiPupMenuEnd(C, pup); } } From 17c083a38f3a5269a3224b632f0bc129d831dc5d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 14:40:27 +0000 Subject: [PATCH 012/138] 'Add Group' back in the add object menu --- source/blender/editors/object/object_add.c | 78 +++++++++++++++++++ source/blender/editors/object/object_intern.h | 1 + source/blender/editors/object/object_ops.c | 1 + 3 files changed, 80 insertions(+) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 7188368a95f..780126852ed 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -26,6 +26,7 @@ */ #include +#include #include "MEM_guardedalloc.h" @@ -704,6 +705,8 @@ static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *eve uiItemMenuEnumO(layout, "Lamp", ICON_OUTLINER_OB_LAMP, "OBJECT_OT_lamp_add", "type"); uiItemS(layout); uiItemMenuEnumO(layout, "Force Field", ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_effector_add", "type"); + uiItemS(layout); + uiItemMenuEnumO(layout, "Group Instance", ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_group_instance_add", "type"); uiPupMenuEnd(C, pup); @@ -728,6 +731,81 @@ void OBJECT_OT_primitive_add(wmOperatorType *ot) ot->flag= 0; } +/* add dupligroup */ +static EnumPropertyItem *add_dupligroup_itemf(bContext *C, PointerRNA *ptr, int *free) +{ + EnumPropertyItem *item= NULL, item_tmp; + int totitem= 0; + int i= 0; + Group *group; + + if(C==NULL) + return NULL; + + memset(&item_tmp, 0, sizeof(item_tmp)); + + for(group= CTX_data_main(C)->group.first; group; group= group->id.next) { + item_tmp.identifier= item_tmp.name= group->id.name+2; + item_tmp.value= i++; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + + if(i>0) { + *free= 1; + return item; + } + else { + return NULL; + } +} + +static int group_instance_add_exec(bContext *C, wmOperator *op) +{ + /* XXX, using an enum for library lookups is a bit dodgy */ + Group *group= BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "type")); + + if(group) { + Object *ob= object_add_type(C, OB_EMPTY); + rename_id(&ob->id, group->id.name+2); + ob->dup_group= group; + ob->transflag |= OB_DUPLIGROUP; + id_us_plus(&group->id); + + + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +/* only used as menu */ +void OBJECT_OT_group_instance_add(wmOperatorType *ot) +{ + PropertyRNA *prop; + static EnumPropertyItem prop_group_dummy_types[] = { + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name= "Add Group Instance"; + ot->description = "Add a dupligroup instance."; + ot->idname= "OBJECT_OT_group_instance_add"; + + /* api callbacks */ + ot->exec= group_instance_add_exec; + + ot->poll= ED_operator_scene_editable; + + /* flags */ + ot->flag= 0; + + /* properties */ + prop= RNA_def_enum(ot->srna, "type", prop_group_dummy_types, 0, "Type", ""); + RNA_def_enum_funcs(prop, add_dupligroup_itemf); +} + /**************************** Delete Object *************************/ /* remove base from a specific scene */ diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 474715c593b..1a7d3841aaa 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -92,6 +92,7 @@ void OBJECT_OT_armature_add(struct wmOperatorType *ot); void OBJECT_OT_lamp_add(struct wmOperatorType *ot); void OBJECT_OT_primitive_add(struct wmOperatorType *ot); /* only used as menu */ void OBJECT_OT_effector_add(struct wmOperatorType *ot); +void OBJECT_OT_group_instance_add(struct wmOperatorType *ot); void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot); void OBJECT_OT_duplicate(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 91e21e77f3a..82135bf3804 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -118,6 +118,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_lamp_add); WM_operatortype_append(OBJECT_OT_add); WM_operatortype_append(OBJECT_OT_effector_add); + WM_operatortype_append(OBJECT_OT_group_instance_add); WM_operatortype_append(OBJECT_OT_primitive_add); WM_operatortype_append(OBJECT_OT_mesh_add); WM_operatortype_append(OBJECT_OT_metaball_add); From cf4f00b2fa6dfecc400519a635c41798bf45ca88 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 7 Oct 2009 14:48:29 +0000 Subject: [PATCH 013/138] Preview Render: * Fixes for texture and material nodes. * Texture node previews now work more like materials. --- source/blender/editors/include/ED_render.h | 14 ++-- .../blender/editors/render/render_preview.c | 33 +++++--- source/blender/editors/space_node/node_draw.c | 3 + .../blender/editors/space_node/space_node.c | 6 +- source/blender/makesdna/DNA_scene_types.h | 5 +- source/blender/makesrna/intern/rna_material.c | 2 +- source/blender/makesrna/intern/rna_texture.c | 12 ++- .../blender/nodes/intern/TEX_nodes/TEX_at.c | 2 +- .../nodes/intern/TEX_nodes/TEX_bricks.c | 4 +- .../nodes/intern/TEX_nodes/TEX_checker.c | 4 +- .../nodes/intern/TEX_nodes/TEX_compose.c | 2 +- .../nodes/intern/TEX_nodes/TEX_coord.c | 4 +- .../nodes/intern/TEX_nodes/TEX_curves.c | 4 +- .../nodes/intern/TEX_nodes/TEX_decompose.c | 8 +- .../nodes/intern/TEX_nodes/TEX_distance.c | 4 +- .../nodes/intern/TEX_nodes/TEX_hueSatVal.c | 2 +- .../nodes/intern/TEX_nodes/TEX_image.c | 4 +- .../nodes/intern/TEX_nodes/TEX_invert.c | 4 +- .../blender/nodes/intern/TEX_nodes/TEX_math.c | 4 +- .../nodes/intern/TEX_nodes/TEX_mixRgb.c | 4 +- .../nodes/intern/TEX_nodes/TEX_output.c | 44 +++++------ .../blender/nodes/intern/TEX_nodes/TEX_proc.c | 5 +- .../nodes/intern/TEX_nodes/TEX_rotate.c | 2 +- .../nodes/intern/TEX_nodes/TEX_scale.c | 2 +- .../nodes/intern/TEX_nodes/TEX_texture.c | 4 +- .../nodes/intern/TEX_nodes/TEX_translate.c | 2 +- .../nodes/intern/TEX_nodes/TEX_valToNor.c | 4 +- .../nodes/intern/TEX_nodes/TEX_valToRgb.c | 6 +- .../nodes/intern/TEX_nodes/TEX_viewer.c | 11 ++- source/blender/nodes/intern/TEX_util.c | 75 ++++--------------- source/blender/nodes/intern/TEX_util.h | 5 +- .../blender/render/intern/source/shadeinput.c | 2 +- source/blender/render/intern/source/texture.c | 2 +- 33 files changed, 127 insertions(+), 162 deletions(-) diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index be93bf92e5e..13028dac1a2 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -64,21 +64,19 @@ typedef struct RenderInfo { /* Render the preview pr_method: -- PR_DRAW_RENDER: preview is rendered and drawn, as indicated by called context (buttons panel) -- PR_ICON_RENDER: the preview is not drawn and the function is not dynamic, - so no events are processed. Hopefully fast enough for at least 32x32 -- PR_DO_RENDER: preview is rendered, not drawn, but events are processed for afterqueue, - in use for node editor now. +- PR_BUTS_RENDER: preview is rendered for buttons window +- PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32 +- PR_NODE_RENDER: preview is rendered for node editor. */ -#define PR_DRAW_RENDER 0 +#define PR_BUTS_RENDER 0 #define PR_ICON_RENDER 1 -#define PR_DO_RENDER 2 +#define PR_NODE_RENDER 2 void ED_preview_init_dbase(void); void ED_preview_free_dbase(void); -void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey); +void ED_preview_shader_job(const struct bContext *C, void *owner, struct ID *id, struct ID *parent, struct MTex *slot, int sizex, int sizey, int method); void ED_preview_icon_job(const struct bContext *C, void *owner, struct ID *id, unsigned int *rect, int sizex, int sizey); void ED_preview_draw(const struct bContext *C, void *idp, void *parentp, void *slot, rcti *rect); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 4a671e4d2ba..92380a56d3d 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -359,7 +359,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre } else { sce->lay= 1<pr_type; - if(mat->nodetree) + if(mat->nodetree && sp->pr_method==PR_NODE_RENDER) ntreeInitPreview(mat->nodetree, sp->sizex, sp->sizey); } } @@ -408,6 +408,9 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre } } } + + if(tex && tex->nodetree && sp->pr_method==PR_NODE_RENDER) + ntreeInitPreview(tex->nodetree, sp->sizex, sp->sizey); } else if(id_type==ID_LA) { Lamp *la= (Lamp *)id; @@ -529,7 +532,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r } if(ok==0) { - ED_preview_shader_job(C, sa, id, parent, slot, newx, newy); + ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER); } } } @@ -880,11 +883,12 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs Render *re; Scene *sce; float oldlens; + short idtype= GS(id->name); char name[32]; int sizex; /* get the stuff from the builtin preview dbase */ - sce= preview_prepare_scene(sp->scene, id, GS(id->name), sp); // XXX sizex + sce= preview_prepare_scene(sp->scene, id, idtype, sp); // XXX sizex if(sce==NULL) return; if(!split || first) sprintf(name, "Preview %p", sp->owner); @@ -896,14 +900,19 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs re= RE_NewRender(name); /* sce->r gets copied in RE_InitState! */ - if(sp->pr_method==PR_DO_RENDER) { - sce->r.scemode |= R_NODE_PREVIEW; - sce->r.scemode &= ~R_NO_IMAGE_LOAD; + sce->r.scemode &= ~(R_MATNODE_PREVIEW|R_TEXNODE_PREVIEW); + sce->r.scemode &= ~R_NO_IMAGE_LOAD; + + if(sp->pr_method==PR_ICON_RENDER) { + sce->r.scemode |= R_NO_IMAGE_LOAD; + } + else if(sp->pr_method==PR_NODE_RENDER) { + if(idtype == ID_MA) sce->r.scemode |= R_MATNODE_PREVIEW; + else if(idtype == ID_TE) sce->r.scemode |= R_TEXNODE_PREVIEW; sce->r.mode |= R_OSA; } - else { /* PR_ICON_RENDER */ - sce->r.scemode &= ~R_NODE_PREVIEW; - sce->r.scemode |= R_NO_IMAGE_LOAD; + else { /* PR_BUTS_RENDER */ + sce->r.mode |= R_OSA; } /* in case of split preview, use border render */ @@ -917,7 +926,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs RE_InitState(re, NULL, &sce->r, sizex, sp->sizey, NULL); /* callbacs are cleared on GetRender() */ - if(sp->pr_method==PR_DO_RENDER) { + if(sp->pr_method==PR_BUTS_RENDER) { RE_display_draw_cb(re, sp, shader_preview_draw); RE_test_break_cb(re, sp, shader_preview_break); } @@ -1125,7 +1134,7 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r WM_jobs_start(CTX_wm_manager(C), steve); } -void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey) +void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, int method) { wmJob *steve; ShaderPreview *sp; @@ -1138,7 +1147,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M sp->owner= owner; sp->sizex= sizex; sp->sizey= sizey; - sp->pr_method= PR_DO_RENDER; + sp->pr_method= method; sp->id = id; sp->parent= parent; sp->slot= slot; diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 3fc91fea914..dd2dc0d796a 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -54,6 +54,7 @@ #include "MEM_guardedalloc.h" #include "BKE_context.h" +#include "BKE_depsgraph.h" #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" @@ -102,6 +103,7 @@ void ED_node_changed_update(bContext *C, bNode *node) return; if(snode->treetype==NTREE_SHADER) { + DAG_id_flush_update(snode->id, 0); WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, snode->id); } else if(snode->treetype==NTREE_COMPOSIT) { @@ -127,6 +129,7 @@ void ED_node_changed_update(bContext *C, bNode *node) WM_event_add_notifier(C, NC_SCENE|ND_NODES, CTX_data_scene(C)); } else if(snode->treetype==NTREE_TEXTURE) { + DAG_id_flush_update(snode->id, 0); WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id); } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 2cfd9d99123..bdd2a65984f 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -179,12 +179,14 @@ static void node_area_refresh(const struct bContext *C, struct ScrArea *sa) { /* default now: refresh node is starting preview */ SpaceNode *snode= sa->spacedata.first; + + snode_set_context(snode, CTX_data_scene(C)); if(snode->nodetree) { if(snode->treetype==NTREE_SHADER) { Material *ma= (Material *)snode->id; if(ma->use_nodes) - ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100); + ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); } else if(snode->treetype==NTREE_COMPOSIT) { Scene *scene= (Scene *)snode->id; @@ -194,7 +196,7 @@ static void node_area_refresh(const struct bContext *C, struct ScrArea *sa) else if(snode->treetype==NTREE_TEXTURE) { Tex *tex= (Tex *)snode->id; if(tex->use_nodes) { - ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100); + ED_preview_shader_job(C, sa, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); } } } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 63415662d2b..437b45cfda1 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -840,7 +840,7 @@ typedef struct Scene { #define R_PASSEPARTOUT 0x0004 #define R_PREVIEWBUTS 0x0008 #define R_EXTENSION 0x0010 -#define R_NODE_PREVIEW 0x0020 +#define R_MATNODE_PREVIEW 0x0020 #define R_DOCOMP 0x0040 #define R_COMP_CROP 0x0080 #define R_FREE_IMAGE 0x0100 @@ -852,7 +852,8 @@ typedef struct Scene { #define R_STAMP_INFO 0x4000 /* deprecated */ #define R_FULL_SAMPLE 0x8000 #define R_COMP_RERENDER 0x10000 -#define R_RECURS_PROTECTION 0x20000 +#define R_RECURS_PROTECTION 0x20000 +#define R_TEXNODE_PREVIEW 0x40000 /* r->stamp */ #define R_STAMP_TIME 0x0001 diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 9ad42174413..28fcc3103b8 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1716,7 +1716,7 @@ void RNA_def_material(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1); RNA_def_property_boolean_funcs(prop, NULL, "rna_Material_use_nodes_set"); RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes to render the material."); - RNA_def_property_update(prop, NC_MATERIAL, NULL); + RNA_def_property_update(prop, 0, "rna_Material_update"); prop= RNA_def_property(srna, "active_node_material", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Material"); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 78d7f012487..428df15ef4e 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -107,6 +107,14 @@ static void rna_Texture_update(bContext *C, PointerRNA *ptr) WM_event_add_notifier(C, NC_TEXTURE, tex); } +static void rna_Texture_nodes_update(bContext *C, PointerRNA *ptr) +{ + Tex *tex= ptr->id.data; + + DAG_id_flush_update(&tex->id, 0); + WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, tex); +} + static void rna_Texture_type_set(PointerRNA *ptr, int value) { Tex *tex= (Tex*)ptr->data; @@ -1678,12 +1686,12 @@ static void rna_def_texture(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1); RNA_def_property_boolean_funcs(prop, NULL, "rna_Texture_use_nodes_set"); RNA_def_property_ui_text(prop, "Use Nodes", "Make this a node-based texture"); - RNA_def_property_update(prop, 0, "rna_Texture_update"); + RNA_def_property_update(prop, 0, "rna_Texture_nodes_update"); prop= RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "nodetree"); RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based textures"); - RNA_def_property_update(prop, 0, "rna_Texture_update"); + RNA_def_property_update(prop, 0, "rna_Texture_nodes_update"); rna_def_animdata_common(srna); diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_at.c b/source/blender/nodes/intern/TEX_nodes/TEX_at.c index 4d714d91130..7e6cce9f35a 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_at.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_at.c @@ -50,7 +50,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_at = { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_bricks.c b/source/blender/nodes/intern/TEX_nodes/TEX_bricks.c index f1f3b0919ae..2093679e39d 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_bricks.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_bricks.c @@ -109,9 +109,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_bricks= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_checker.c b/source/blender/nodes/intern/TEX_nodes/TEX_checker.c index b889f1e2164..7b736206c51 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_checker.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_checker.c @@ -61,9 +61,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_checker= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_compose.c b/source/blender/nodes/intern/TEX_nodes/TEX_compose.c index 9fc4b2ff7c2..dac6ca7c3ef 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_compose.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_compose.c @@ -49,7 +49,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_compose= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_coord.c b/source/blender/nodes/intern/TEX_nodes/TEX_coord.c index e5c2b309fb3..a33a2608af0 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_coord.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_coord.c @@ -42,9 +42,7 @@ static void vectorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, sho static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &vectorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &vectorfn, data); } bNodeType tex_node_coord= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_curves.c b/source/blender/nodes/intern/TEX_nodes/TEX_curves.c index 61ebcea7360..a1b20370687 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_curves.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_curves.c @@ -50,7 +50,7 @@ static void time_colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, static void time_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &time_colorfn); + tex_output(node, in, out[0], &time_colorfn, data); } @@ -100,7 +100,7 @@ static void rgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, static void rgb_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &rgb_colorfn); + tex_output(node, in, out[0], &rgb_colorfn, data); } static void rgb_init(bNode *node) diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_decompose.c b/source/blender/nodes/intern/TEX_nodes/TEX_decompose.c index f7a409f0230..d5eeba2253c 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_decompose.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_decompose.c @@ -67,10 +67,10 @@ static void valuefn_a(float *out, TexParams *p, bNode *node, bNodeStack **in, sh static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &valuefn_r); - tex_output(node, in, out[1], &valuefn_g); - tex_output(node, in, out[2], &valuefn_b); - tex_output(node, in, out[3], &valuefn_a); + tex_output(node, in, out[0], &valuefn_r, data); + tex_output(node, in, out[1], &valuefn_g, data); + tex_output(node, in, out[2], &valuefn_b, data); + tex_output(node, in, out[3], &valuefn_a, data); } bNodeType tex_node_decompose= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_distance.c b/source/blender/nodes/intern/TEX_nodes/TEX_distance.c index 4e145e26b72..297fc02939d 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_distance.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_distance.c @@ -53,9 +53,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &valuefn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &valuefn, data); } bNodeType tex_node_distance= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_hueSatVal.c b/source/blender/nodes/intern/TEX_nodes/TEX_hueSatVal.c index 192c7a39ee8..b267dc7acbb 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_hueSatVal.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_hueSatVal.c @@ -84,7 +84,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_hue_sat= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_image.c b/source/blender/nodes/intern/TEX_nodes/TEX_image.c index 0a55af70b52..123063a7900 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_image.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_image.c @@ -73,9 +73,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &colorfn, data); } static void init(bNode* node) diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_invert.c b/source/blender/nodes/intern/TEX_nodes/TEX_invert.c index 5663f897ff5..f2fcbfbf9eb 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_invert.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_invert.c @@ -55,9 +55,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_invert= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_math.c b/source/blender/nodes/intern/TEX_nodes/TEX_math.c index 4ee04140fca..8c400a44832 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_math.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_math.c @@ -171,9 +171,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &valuefn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &valuefn, data); } bNodeType tex_node_math= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_mixRgb.c b/source/blender/nodes/intern/TEX_nodes/TEX_mixRgb.c index 24bdde70127..f6955b47376 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_mixRgb.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_mixRgb.c @@ -57,9 +57,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_mix_rgb= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_output.c b/source/blender/nodes/intern/TEX_nodes/TEX_output.c index 7ce5ec88c48..140c31a7986 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_output.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_output.c @@ -83,28 +83,30 @@ static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) TexCallData *cdata = (TexCallData *)data; TexResult *target = cdata->target; - if(in[1]->hasinput && !in[0]->hasinput) - tex_do_preview(node, in[1], data); - else - tex_do_preview(node, in[0], data); + if(cdata->do_preview) { + TexParams params; + params_from_cdata(¶ms, cdata); + + if(in[1]->hasinput && !in[0]->hasinput) + tex_input_rgba(&target->tr, in[1], ¶ms, cdata->thread); + else + tex_input_rgba(&target->tr, in[0], ¶ms, cdata->thread); + tex_do_preview(node, params.coord, &target->tr); + } + else if(cdata->which_output == node->custom1) { + TexParams params; + params_from_cdata(¶ms, cdata); + + osa(tex_input_rgba, &target->tr, in[0], ¶ms, cdata->thread); - if(!cdata->do_preview) { - if(cdata->which_output == node->custom1) - { - TexParams params; - params_from_cdata(¶ms, cdata); - - osa(tex_input_rgba, &target->tr, in[0], ¶ms, cdata->thread); - - target->tin = (target->tr + target->tg + target->tb) / 3.0f; - target->talpha = 1.0f; - - if(target->nor) { - if(in[1]->hasinput) - osa(tex_input_vec, target->nor, in[1], ¶ms, cdata->thread); - else - target->nor = 0; - } + target->tin = (target->tr + target->tg + target->tb) / 3.0f; + target->talpha = 1.0f; + + if(target->nor) { + if(in[1]->hasinput) + osa(tex_input_vec, target->nor, in[1], ¶ms, cdata->thread); + else + target->nor = 0; } } } diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_proc.c b/source/blender/nodes/intern/TEX_nodes/TEX_proc.c index ce7324e2085..9f355e6d8f0 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_proc.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_proc.c @@ -125,9 +125,8 @@ static int count_outputs(bNode *node) static void name##_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) \ { \ int outs = count_outputs(node); \ - if(outs >= 1) tex_output(node, in, out[0], &name##_colorfn); \ - if(outs >= 2) tex_output(node, in, out[1], &name##_normalfn); \ - if(outs >= 1) tex_do_preview(node, out[0], data); \ + if(outs >= 1) tex_output(node, in, out[0], &name##_colorfn, data); \ + if(outs >= 2) tex_output(node, in, out[1], &name##_normalfn, data); \ } diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_rotate.c b/source/blender/nodes/intern/TEX_nodes/TEX_rotate.c index bdf5a1ce079..2184d32fcf2 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_rotate.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_rotate.c @@ -95,7 +95,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor } static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_rotate= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_scale.c b/source/blender/nodes/intern/TEX_nodes/TEX_scale.c index 3d4415365aa..205549c97d9 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_scale.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_scale.c @@ -56,7 +56,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor } static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_scale = { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_texture.c b/source/blender/nodes/intern/TEX_nodes/TEX_texture.c index 0ca80a82271..d0536a8fda8 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_texture.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_texture.c @@ -79,9 +79,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_texture= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_translate.c b/source/blender/nodes/intern/TEX_nodes/TEX_translate.c index ba3dcfa27a2..c2f7377da3b 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_translate.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_translate.c @@ -56,7 +56,7 @@ static void colorfn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor } static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &colorfn); + tex_output(node, in, out[0], &colorfn, data); } bNodeType tex_node_translate = { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_valToNor.c b/source/blender/nodes/intern/TEX_nodes/TEX_valToNor.c index 75b88c3a460..6b8349e90af 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_valToNor.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_valToNor.c @@ -72,9 +72,7 @@ static void normalfn(float *out, TexParams *p, bNode *node, bNodeStack **in, sho } static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &normalfn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &normalfn, data); } bNodeType tex_node_valtonor = { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_valToRgb.c b/source/blender/nodes/intern/TEX_nodes/TEX_valToRgb.c index 90a444bcff0..669f45ec89a 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_valToRgb.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_valToRgb.c @@ -50,7 +50,7 @@ static void valtorgb_colorfn(float *out, TexParams *p, bNode *node, bNodeStack * static void valtorgb_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &valtorgb_colorfn); + tex_output(node, in, out[0], &valtorgb_colorfn, data); } static void valtorgb_init(bNode *node) @@ -97,9 +97,7 @@ static void rgbtobw_valuefn(float *out, TexParams *p, bNode *node, bNodeStack ** static void rgbtobw_exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_output(node, in, out[0], &rgbtobw_valuefn); - - tex_do_preview(node, out[0], data); + tex_output(node, in, out[0], &rgbtobw_valuefn, data); } bNodeType tex_node_rgbtobw= { diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_viewer.c b/source/blender/nodes/intern/TEX_nodes/TEX_viewer.c index 2d29b03b38c..5ebd971d9fb 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_viewer.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_viewer.c @@ -39,7 +39,16 @@ static bNodeSocketType outputs[]= { static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) { - tex_do_preview(node, in[0], data); + TexCallData *cdata = (TexCallData *)data; + + if(cdata->do_preview) { + TexParams params; + float col[4]; + params_from_cdata(¶ms, cdata); + + tex_input_rgba(col, in[0], ¶ms, cdata->thread); + tex_do_preview(node, params.coord, col); + } } bNodeType tex_node_viewer = { diff --git a/source/blender/nodes/intern/TEX_util.c b/source/blender/nodes/intern/TEX_util.c index f2333ffcf2e..867bbd8c14e 100644 --- a/source/blender/nodes/intern/TEX_util.c +++ b/source/blender/nodes/intern/TEX_util.c @@ -49,8 +49,12 @@ void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread) { - if(dg->node->need_exec) + if(dg->node->need_exec) { dg->fn(out, params, dg->node, dg->in, thread); + + if(dg->cdata->do_preview) + tex_do_preview(dg->node, params->coord, out); + } } void tex_input(float *out, int sz, bNodeStack *in, TexParams *params, short thread) @@ -95,26 +99,6 @@ float tex_input_value(bNodeStack *in, TexParams *params, short thread) return out[0]; } -static void init_preview(bNode *node) -{ - int xsize = (int)(node->prvr.xmax - node->prvr.xmin); - int ysize = (int)(node->prvr.ymax - node->prvr.ymin); - - if(xsize == 0) { - xsize = PREV_RES; - ysize = PREV_RES; - } - - if(node->preview==NULL) - node->preview= MEM_callocN(sizeof(bNodePreview), "node preview"); - - if(node->preview->rect==NULL) { - node->preview->rect= MEM_callocN(4*xsize + xsize*ysize*sizeof(float)*4, "node preview rect"); - node->preview->xsize= xsize; - node->preview->ysize= ysize; - } -} - void params_from_cdata(TexParams *out, TexCallData *in) { out->coord = in->coord; @@ -123,48 +107,19 @@ void params_from_cdata(TexParams *out, TexCallData *in) out->cfra = in->cfra; } -void tex_do_preview(bNode *node, bNodeStack *ns, TexCallData *cdata) +void tex_do_preview(bNode *node, float *coord, float *col) { - int x, y; - float *result; - bNodePreview *preview; - float coord[3] = {0, 0, 0}; - TexParams params; - int resolution; - int xsize, ysize; - - if(!cdata->do_preview) - return; - - if(!(node->typeinfo->flag & NODE_PREVIEW)) - return; - - init_preview(node); - - preview = node->preview; - xsize = preview->xsize; - ysize = preview->ysize; - - params.dxt = 0; - params.dyt = 0; - params.cfra = cdata->cfra; - params.coord = coord; - - resolution = (xsize < ysize) ? xsize : ysize; - - for(x=0; xrect + 4 * (xsize*y + x); - - tex_input_rgba(result, ns, ¶ms, cdata->thread); + bNodePreview *preview= node->preview; + + if(preview) { + int xs= ((coord[0] + 1.0f)*0.5f)*preview->xsize; + int ys= ((coord[1] + 1.0f)*0.5f)*preview->ysize; + + nodeAddToPreview(node, col, xs, ys); } } -void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn) +void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn, TexCallData *cdata) { TexDelegate *dg; if(!out->data) @@ -173,7 +128,7 @@ void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn) else dg = out->data; - + dg->cdata= cdata; dg->fn = texfn; dg->node = node; memcpy(dg->in, in, MAX_SOCKET * sizeof(bNodeStack*)); diff --git a/source/blender/nodes/intern/TEX_util.h b/source/blender/nodes/intern/TEX_util.h index fd3d47f4729..14e2773414a 100644 --- a/source/blender/nodes/intern/TEX_util.h +++ b/source/blender/nodes/intern/TEX_util.h @@ -87,6 +87,7 @@ typedef struct TexParams { typedef void(*TexFn) (float *out, TexParams *params, bNode *node, bNodeStack **in, short thread); typedef struct TexDelegate { + TexCallData *cdata; TexFn fn; bNode *node; bNodeStack *in[MAX_SOCKET]; @@ -99,8 +100,8 @@ void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread) void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread); float tex_input_value(bNodeStack *in, TexParams *params, short thread); -void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn); -void tex_do_preview(bNode *node, bNodeStack *ns, TexCallData *cdata); +void tex_output(bNode *node, bNodeStack **in, bNodeStack *out, TexFn texfn, TexCallData *data); +void tex_do_preview(bNode *node, float *coord, float *col); void params_from_cdata(TexParams *out, TexCallData *in); diff --git a/source/blender/render/intern/source/shadeinput.c b/source/blender/render/intern/source/shadeinput.c index e5684e2ebe9..30ff213b95b 100644 --- a/source/blender/render/intern/source/shadeinput.c +++ b/source/blender/render/intern/source/shadeinput.c @@ -1306,7 +1306,7 @@ void shade_input_initialize(ShadeInput *shi, RenderPart *pa, RenderLayer *rl, in shi->sample= sample; shi->thread= pa->thread; - shi->do_preview= R.r.scemode & R_NODE_PREVIEW; + shi->do_preview= (R.r.scemode & R_MATNODE_PREVIEW) != 0; shi->lay= rl->lay; shi->layflag= rl->layflag; shi->passflag= rl->passflag; diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index 7b0e5d8abbc..aee2d8d1866 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -721,7 +721,7 @@ static int evalnodes(Tex *tex, float *texvec, float *dxt, float *dyt, TexResult short rv = TEX_INT; bNodeTree *nodes = tex->nodetree; - ntreeTexExecTree(nodes, texres, texvec, dxt, dyt, thread, tex, which_output, R.r.cfra, (R.r.scemode & R_NODE_PREVIEW)); + ntreeTexExecTree(nodes, texres, texvec, dxt, dyt, thread, tex, which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0); if(texres->nor) rv |= TEX_NOR; rv |= TEX_RGB; From 93b5375ca17a44fbe225f7af135dc0d647d32dd4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 15:16:08 +0000 Subject: [PATCH 014/138] Making new faces (fkey, scanfill etc) didnt create faces with the active material. Keep the editmesh material and active material in sync --- source/blender/editors/mesh/editmesh.c | 2 ++ source/blender/makesrna/intern/rna_object.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 980d699dda5..d540151337d 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -986,6 +986,8 @@ void load_editMesh(Scene *scene, Object *ob) CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface); mesh_update_customdata_pointers(me); + em->mat_nr= ob->actcol-1; + /* the vertices, use ->tmp.l as counter */ eve= em->verts.first; a= 0; diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 3a3842adbf1..4fb2db42b8b 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -99,6 +99,8 @@ EnumPropertyItem object_type_items[] = { #include "BKE_particle.h" #include "BKE_scene.h" +#include "BLI_editVert.h" /* for EditMesh->mat_nr */ + #include "ED_object.h" void rna_Object_update(bContext *C, PointerRNA *ptr) @@ -404,6 +406,13 @@ static void rna_Object_active_material_index_set(PointerRNA *ptr, int value) { Object *ob= (Object*)ptr->id.data; ob->actcol= value+1; + + if(ob->mode==OB_MODE_EDIT && ob->type==OB_MESH) { + Mesh *me= ob->data; + + if(me->edit_mesh) + me->edit_mesh->mat_nr= value; + } } static void rna_Object_active_material_index_range(PointerRNA *ptr, int *min, int *max) From df63ccd904f28c3796f15ae14afcb18b45831fe9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 7 Oct 2009 16:10:06 +0000 Subject: [PATCH 015/138] Transform Mirror: * Make Ctrl+M key work for mirror in 3D view. * Fix mirror along global axis, was mirroring around all axes when the object was rotated, due to wrong matrix order, was also not working in 2.4. * Pressing e.g. X twice still doesn't go to local mode, would fix but don't know how the code is intended to work. --- source/blender/editors/transform/transform.c | 2 +- source/blender/editors/transform/transform_ops.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b109157d859..07aedf5e78e 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2334,7 +2334,7 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) { if (t->flag & (T_OBJECT|T_TEXTURE|T_POSE)) { float obsizemat[3][3]; // Reorient the size mat to fit the oriented object. - Mat3MulMat3(obsizemat, tmat, td->axismtx); + Mat3MulMat3(obsizemat, td->axismtx, tmat); //printmatrix3("obsizemat", obsizemat); TransMat3ToSize(obsizemat, td->axismtx, fsize); //printvecf("fsize", fsize); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 0440a957539..7ef8ad17a69 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -767,6 +767,8 @@ void transform_keymap_for_space(struct wmWindowManager *wm, struct wmKeyMap *key km = WM_keymap_add_item(keymap, "TFM_OT_create_orientation", SPACEKEY, KM_PRESS, KM_CTRL|KM_ALT, 0); RNA_boolean_set(km->ptr, "use", 1); + km = WM_keymap_add_item(keymap, "TFM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0); + break; case SPACE_ACTION: km= WM_keymap_add_item(keymap, "TFM_OT_transform", GKEY, KM_PRESS, 0, 0); @@ -837,7 +839,7 @@ void transform_keymap_for_space(struct wmWindowManager *wm, struct wmKeyMap *key km = WM_keymap_add_item(keymap, "TFM_OT_resize", SKEY, KM_PRESS, 0, 0); - km = WM_keymap_add_item(keymap, "TFM_OT_mirror", MKEY, KM_PRESS, 0, 0); + km = WM_keymap_add_item(keymap, "TFM_OT_mirror", MKEY, KM_PRESS, KM_CTRL, 0); break; default: break; From 763358fe913c9ede43921f3ccc4cd6fdbfc5f809 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 16:32:55 +0000 Subject: [PATCH 016/138] copy icon in the material buttons list view so you can copy the current set of materials to other selected objects, (like Ctrl+L, Materials in 2.4x) --- release/scripts/ui/buttons_material.py | 1 + source/blender/blenkernel/BKE_material.h | 1 + source/blender/blenkernel/intern/material.c | 19 ++++++++++ source/blender/editors/render/render_intern.h | 1 + source/blender/editors/render/render_ops.c | 1 + .../blender/editors/render/render_shading.c | 38 +++++++++++++++++++ 6 files changed, 61 insertions(+) diff --git a/release/scripts/ui/buttons_material.py b/release/scripts/ui/buttons_material.py index e91e324f49d..03e11e003e2 100644 --- a/release/scripts/ui/buttons_material.py +++ b/release/scripts/ui/buttons_material.py @@ -59,6 +59,7 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel): col = row.column(align=True) col.itemO("object.material_slot_add", icon='ICON_ZOOMIN', text="") col.itemO("object.material_slot_remove", icon='ICON_ZOOMOUT', text="") + col.itemO("object.material_slot_copy", icon='ICON_COPYDOWN', text="") if ob.mode == 'EDIT': row = layout.row(align=True) diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 382754ee2b2..b6645ef8737 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -58,6 +58,7 @@ short *give_totcolp(struct Object *ob); struct Material *give_current_material(struct Object *ob, int act); struct ID *material_from(struct Object *ob, int act); void assign_material(struct Object *ob, struct Material *ma, int act); +void assign_matarar(struct Object *ob, struct Material ***matar, int totcol); int find_material_index(struct Object *ob, struct Material *ma); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 7e742dc5631..b44c59baaca 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -625,6 +625,25 @@ void assign_material(Object *ob, Material *ma, int act) test_object_materials(ob->data); } +/* XXX - this calls many more update calls per object then are needed, could be optimized */ +void assign_matarar(struct Object *ob, struct Material ***matar, int totcol) +{ + int i, actcol_orig= ob->actcol; + + while(ob->totcol) + object_remove_material_slot(ob); + + /* now we have the right number of slots */ + for(i=0; i ob->totcol) + actcol_orig= ob->totcol; + + ob->actcol= actcol_orig; +} + + int find_material_index(Object *ob, Material *ma) { Material ***matarar; diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h index dccc2d36002..d3ecbbc56e8 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.h @@ -37,6 +37,7 @@ void OBJECT_OT_material_slot_remove(struct wmOperatorType *ot); void OBJECT_OT_material_slot_assign(struct wmOperatorType *ot); void OBJECT_OT_material_slot_select(struct wmOperatorType *ot); void OBJECT_OT_material_slot_deselect(struct wmOperatorType *ot); +void OBJECT_OT_material_slot_copy(struct wmOperatorType *ot); void MATERIAL_OT_new(struct wmOperatorType *ot); void TEXTURE_OT_new(struct wmOperatorType *ot); diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c index 8b60582d466..7d35dff7493 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.c @@ -43,6 +43,7 @@ void ED_operatortypes_render(void) WM_operatortype_append(OBJECT_OT_material_slot_assign); WM_operatortype_append(OBJECT_OT_material_slot_select); WM_operatortype_append(OBJECT_OT_material_slot_deselect); + WM_operatortype_append(OBJECT_OT_material_slot_copy); WM_operatortype_append(MATERIAL_OT_new); WM_operatortype_append(TEXTURE_OT_new); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 56605ad0970..26df0df935b 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -431,6 +431,44 @@ void OBJECT_OT_material_slot_deselect(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; } + +static int material_slot_copy_exec(bContext *C, wmOperator *op) +{ + Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; + Material ***matar; + + if(!ob || !(matar= give_matarar(ob))) + return OPERATOR_CANCELLED; + + CTX_DATA_BEGIN(C, Object*, ob_iter, selected_editable_objects) { + if(ob != ob_iter && give_matarar(ob_iter)) { + assign_matarar(ob_iter, matar, ob->totcol); + if(ob_iter->totcol==ob->totcol) { + ob_iter->actcol= ob->actcol; + WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, ob_iter); + } + } + } + CTX_DATA_END; + + return OPERATOR_FINISHED; +} + + +void OBJECT_OT_material_slot_copy(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Copy Material to Others"; + ot->idname= "OBJECT_OT_material_slot_copy"; + ot->description="Copies materials to other selected objects."; + + /* api callbacks */ + ot->exec= material_slot_copy_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; +} + /********************** new material operator *********************/ static int new_material_exec(bContext *C, wmOperator *op) From ef13a40fed9931cce7db389d50fda547f35a951c Mon Sep 17 00:00:00 2001 From: Diego Borghetti Date: Wed, 7 Oct 2009 19:29:39 +0000 Subject: [PATCH 017/138] Makefile: Add missing raytrace directory. --- source/blender/render/intern/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/render/intern/Makefile b/source/blender/render/intern/Makefile index 859a813bd2f..4fce37df175 100644 --- a/source/blender/render/intern/Makefile +++ b/source/blender/render/intern/Makefile @@ -29,6 +29,6 @@ # Bounces make to subdirectories. SOURCEDIR = source/blender/render/intern -DIRS = source +DIRS = source raytrace include nan_subdirs.mk From a4e36f24c74dfc825347752aae2e55e0247924ef Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Wed, 7 Oct 2009 20:55:14 +0000 Subject: [PATCH 018/138] [#19354] Second press of axis key didn't do local orientation when global was selected as user orientation (frankly, I don't like it much to have an exception for that, but backward compatibility is ok, unless someone else has a strong argument against). --- source/blender/editors/transform/transform.c | 17 ++++++++++------- source/blender/editors/transform/transform.h | 2 +- .../editors/transform/transform_constraints.c | 5 ++--- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 07aedf5e78e..b5920210381 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -773,10 +773,11 @@ void transformEvent(TransInfo *t, wmEvent *event) stopConstraint(t); } else { + short orientation = t->current_orientation != V3D_MANIP_GLOBAL ? t->current_orientation : V3D_MANIP_LOCAL; if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) - setUserConstraint(t, (CON_AXIS0), "along %s X"); + setUserConstraint(t, orientation, (CON_AXIS0), "along %s X"); else if (t->modifiers & MOD_CONSTRAINT_PLANE) - setUserConstraint(t, (CON_AXIS1|CON_AXIS2), "locking %s X"); + setUserConstraint(t, orientation, (CON_AXIS1|CON_AXIS2), "locking %s X"); } } } @@ -805,10 +806,11 @@ void transformEvent(TransInfo *t, wmEvent *event) stopConstraint(t); } else { + short orientation = t->current_orientation != V3D_MANIP_GLOBAL ? t->current_orientation : V3D_MANIP_LOCAL; if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) - setUserConstraint(t, (CON_AXIS1), "along %s Y"); + setUserConstraint(t, orientation, (CON_AXIS1), "along %s Y"); else if (t->modifiers & MOD_CONSTRAINT_PLANE) - setUserConstraint(t, (CON_AXIS0|CON_AXIS2), "locking %s Y"); + setUserConstraint(t, orientation, (CON_AXIS0|CON_AXIS2), "locking %s Y"); } } } @@ -833,10 +835,11 @@ void transformEvent(TransInfo *t, wmEvent *event) stopConstraint(t); } else { + short orientation = t->current_orientation != V3D_MANIP_GLOBAL ? t->current_orientation : V3D_MANIP_LOCAL; if ((t->modifiers & MOD_CONSTRAINT_PLANE) == 0) - setUserConstraint(t, (CON_AXIS2), "along %s Z"); + setUserConstraint(t, orientation, (CON_AXIS2), "along %s Z"); else if ((t->modifiers & MOD_CONSTRAINT_PLANE) && ((t->flag & T_2D_EDIT)==0)) - setUserConstraint(t, (CON_AXIS0|CON_AXIS1), "locking %s Z"); + setUserConstraint(t, orientation, (CON_AXIS0|CON_AXIS1), "locking %s Z"); } } else if ((t->flag & T_2D_EDIT)==0) { @@ -1511,7 +1514,7 @@ int initTransform(bContext *C, TransInfo *t, wmOperator *op, wmEvent *event, int t->con.mode |= CON_AXIS2; } - setUserConstraint(t, t->con.mode, "%s"); + setUserConstraint(t, t->current_orientation, t->con.mode, "%s"); } } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 2c19bf932eb..ee6871d67bd 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -548,7 +548,7 @@ void drawConstraint(const struct bContext *C, TransInfo *t); void getConstraintMatrix(TransInfo *t); void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); -void setUserConstraint(TransInfo *t, int mode, const char text[]); +void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); void constraintNumInput(TransInfo *t, float vec[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 158ea98c090..1143203217b 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -551,11 +551,10 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) { ftext is a format string passed to sprintf. It will add the name of the orientation where %s is (logically). */ -void setUserConstraint(TransInfo *t, int mode, const char ftext[]) { +void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { char text[40]; - //short twmode= (t->spacetype==SPACE_VIEW3D)? ((View3D*)t->view)->twmode: V3D_MANIP_GLOBAL; - switch(t->current_orientation) { + switch(orientation) { case V3D_MANIP_GLOBAL: { float mtx[3][3]; From 0c857a4f1462a909b111ec4533e1c1f5ab54af4f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 7 Oct 2009 21:19:35 +0000 Subject: [PATCH 019/138] - made ungrab a second function - WM_cursor_ungrab - ungrab can restore the position of the mouse clamped to the window bounds (much nicer for transform) --- intern/ghost/GHOST_C-api.h | 2 +- intern/ghost/GHOST_IWindow.h | 2 +- intern/ghost/intern/GHOST_C-api.cpp | 4 ++-- intern/ghost/intern/GHOST_Window.cpp | 4 ++-- intern/ghost/intern/GHOST_Window.h | 4 ++-- intern/ghost/intern/GHOST_WindowX11.cpp | 24 +++++++++++++++++-- intern/ghost/intern/GHOST_WindowX11.h | 2 +- .../editors/interface/interface_handlers.c | 4 ++-- source/blender/windowmanager/WM_api.h | 3 ++- .../blender/windowmanager/intern/wm_cursors.c | 10 ++++++-- .../windowmanager/intern/wm_event_system.c | 6 ++--- 11 files changed, 46 insertions(+), 19 deletions(-) diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 35391d3f4cf..00d2cdb1e3b 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -376,7 +376,7 @@ extern GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, * @return Indication of success. */ extern GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, - int grab, int warp); + int grab, int warp, int restore); /*************************************************************************************** ** Access to mouse button and keyboard states. diff --git a/intern/ghost/GHOST_IWindow.h b/intern/ghost/GHOST_IWindow.h index 44ddf9a7cfb..993b41a4d4f 100644 --- a/intern/ghost/GHOST_IWindow.h +++ b/intern/ghost/GHOST_IWindow.h @@ -271,7 +271,7 @@ public: * @param grab The new grab state of the cursor. * @return Indication of success. */ - virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp) { return GHOST_kSuccess; }; + virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp, bool restore) { return GHOST_kSuccess; }; }; diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index b86c4703ea2..e225ad4fd90 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -355,11 +355,11 @@ GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_TSuccess GHOST_SetCursorGrab(GHOST_WindowHandle windowhandle, - int grab, int warp) + int grab, int warp, int restore) { GHOST_IWindow* window = (GHOST_IWindow*) windowhandle; - return window->setCursorGrab(grab?true:false, warp?true:false); + return window->setCursorGrab(grab?true:false, warp?true:false, restore?true:false); } diff --git a/intern/ghost/intern/GHOST_Window.cpp b/intern/ghost/intern/GHOST_Window.cpp index 531674607d1..94feb83e003 100644 --- a/intern/ghost/intern/GHOST_Window.cpp +++ b/intern/ghost/intern/GHOST_Window.cpp @@ -98,12 +98,12 @@ GHOST_TSuccess GHOST_Window::setCursorVisibility(bool visible) } } -GHOST_TSuccess GHOST_Window::setCursorGrab(bool grab, bool warp) +GHOST_TSuccess GHOST_Window::setCursorGrab(bool grab, bool warp, bool restore) { if(m_cursorGrabbed == grab) return GHOST_kSuccess; - if (setWindowCursorGrab(grab, warp)) { + if (setWindowCursorGrab(grab, warp, restore)) { m_cursorGrabbed = grab; return GHOST_kSuccess; } diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 36e4bac6dae..786918716c5 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -175,7 +175,7 @@ public: * @param grab The new grab state of the cursor. * @return Indication of success. */ - virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp); + virtual GHOST_TSuccess setCursorGrab(bool grab, bool warp, bool restore); /** * Sets the window "modified" status, indicating unsaved changes @@ -247,7 +247,7 @@ protected: * Sets the cursor grab on the window using * native window system calls. */ - virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp) { return GHOST_kSuccess; }; + virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp, bool restore) { return GHOST_kSuccess; }; /** * Sets the cursor shape on the window using diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index c2dc1048ea0..d197b534352 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -1400,7 +1400,7 @@ setWindowCursorVisibility( GHOST_TSuccess GHOST_WindowX11:: setWindowCursorGrab( - bool grab, bool warp + bool grab, bool warp, bool restore ){ if(grab) { if(warp) { @@ -1416,7 +1416,27 @@ setWindowCursorGrab( if(m_cursorWarp) { /* are we exiting warp */ setWindowCursorVisibility(true); /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ - m_system->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + if(restore) { + GHOST_Rect bounds; + GHOST_TInt32 x_new, y_new, x_rel, y_rel; + + getClientBounds(bounds); + + x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0]; + y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1]; + + screenToClient(x_new, y_new, x_rel, y_rel); + + if(x_rel < 0) x_new = (x_new-x_rel) + 2; + if(y_rel < 0) y_new = (y_new-y_rel) + 2; + if(x_rel > bounds.getWidth()) x_new -= (x_rel-bounds.getWidth()) + 2; + if(y_rel > bounds.getHeight()) y_new -= (y_rel-bounds.getHeight()) + 2; + m_system->setCursorPosition(x_new, y_new); + + } + else { + m_system->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + } setCursorWarpAccum(0, 0); m_cursorWarp= false; diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 08fba3e2be8..eb0689ab410 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -256,7 +256,7 @@ protected: */ GHOST_TSuccess setWindowCursorGrab( - bool grab, bool warp + bool grab, bool warp, bool restore ); /** diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 385a0eec040..8dea3fa1fc3 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3709,12 +3709,12 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s /* number editing */ if(state == BUTTON_STATE_NUM_EDITING) { if(ui_is_a_warp_but(but)) - WM_cursor_grab(CTX_wm_window(C), 1, 1); + WM_cursor_grab(CTX_wm_window(C), TRUE); ui_numedit_begin(but, data); } else if(data->state == BUTTON_STATE_NUM_EDITING) { ui_numedit_end(but, data); if(ui_is_a_warp_but(but)) - WM_cursor_grab(CTX_wm_window(C), 0, -1); + WM_cursor_ungrab(CTX_wm_window(C), FALSE); } /* menu open */ if(state == BUTTON_STATE_MENU_OPEN) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 321afec51b7..e7f5bb3b291 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -75,7 +75,8 @@ void WM_cursor_set (struct wmWindow *win, int curs); void WM_cursor_modal (struct wmWindow *win, int curs); void WM_cursor_restore (struct wmWindow *win); void WM_cursor_wait (int val); -void WM_cursor_grab (struct wmWindow *win, int val, int warp); +void WM_cursor_grab(struct wmWindow *win, int warp); +void WM_cursor_ungrab(wmWindow *win, int restore); void WM_timecursor (struct wmWindow *win, int nr); void *WM_paint_cursor_activate(struct wmWindowManager *wm, int (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata); diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index d14cde56083..e33132d18b9 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -163,10 +163,16 @@ void WM_cursor_wait(int val) } } -void WM_cursor_grab(wmWindow *win, int val, int warp) +void WM_cursor_grab(wmWindow *win, int warp) { if(win) - GHOST_SetCursorGrab(win->ghostwin, val, warp); + GHOST_SetCursorGrab(win->ghostwin, 1, warp, -1); +} + +void WM_cursor_ungrab(wmWindow *win, int restore) +{ + if(win) + GHOST_SetCursorGrab(win->ghostwin, 0, -1, restore); } /* afer this you can call restore too */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 54841f0e063..086fdd3665b 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -442,7 +442,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P else if(retval & OPERATOR_RUNNING_MODAL) { /* grab cursor during blocking modal ops (X11) */ if(ot->flag & OPTYPE_BLOCKING) - WM_cursor_grab(CTX_wm_window(C), 1, (U.uiflag & USER_CONTINUOUS_MOUSE)); + WM_cursor_grab(CTX_wm_window(C), (U.uiflag & USER_CONTINUOUS_MOUSE)); } else WM_operator_free(op); @@ -637,7 +637,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) CTX_wm_region_set(C, region); } - WM_cursor_grab(CTX_wm_window(C), 0, -1); + WM_cursor_ungrab(CTX_wm_window(C), TRUE); WM_operator_free(handler->op); } else if(handler->ui_remove) { @@ -835,7 +835,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand /* remove modal handler, operator itself should have been cancelled and freed */ if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - WM_cursor_grab(CTX_wm_window(C), 0, -1); + WM_cursor_ungrab(CTX_wm_window(C), TRUE); BLI_remlink(handlers, handler); wm_event_free_handler(handler); From 1b7e5b9abe7c2431d1572cd39d687a139e7acb9a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 7 Oct 2009 21:39:24 +0000 Subject: [PATCH 020/138] WM: test with context-less add notifier. Notifiers are one of the main reasons for passing along context, while actually they don't need much context at all. Might be removed again, but would like to have this especially for RNA API functions. --- source/blender/windowmanager/WM_api.h | 3 ++- .../windowmanager/intern/wm_event_system.c | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index e7f5bb3b291..0054f151803 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -126,7 +126,8 @@ void WM_event_remove_handlers(struct bContext *C, ListBase *handlers); void WM_event_add_mousemove(struct bContext *C); int WM_modal_tweak_exit(struct wmEvent *evt, int tweak_event); -void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *data); +void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); +void WM_main_add_notifier(unsigned int type, void *reference); void wm_event_add (struct wmWindow *win, struct wmEvent *event_to_add); /* XXX only for warning */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 086fdd3665b..4a8aac4525d 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -45,6 +45,7 @@ #include "BKE_context.h" #include "BKE_idprop.h" #include "BKE_global.h" +#include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -118,6 +119,26 @@ void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference note->reference= reference; } +void WM_main_add_notifier(unsigned int type, void *reference) +{ + Main *bmain= G.main; + wmWindowManager *wm= bmain->wm.first; + + if(wm) { + wmNotifier *note= MEM_callocN(sizeof(wmNotifier), "notifier"); + + note->wm= wm; + BLI_addtail(¬e->wm->queue, note); + + note->category= type & NOTE_CATEGORY; + note->data= type & NOTE_DATA; + note->subtype= type & NOTE_SUBTYPE; + note->action= type & NOTE_ACTION; + + note->reference= reference; + } +} + static wmNotifier *wm_notifier_next(wmWindowManager *wm) { wmNotifier *note= wm->queue.first; From fd511eb984a23b63b373e171666667c8213579c0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 7 Oct 2009 22:05:30 +0000 Subject: [PATCH 021/138] Node Bugfixes: * Compo node backdrop works again. * Compo node previews and backdrop now get correct color management float to byte conversion. * Compo nodes got unecessarily recalculated while moving nodes. * Fix compo node viewer nodes not getting activated correctly. * Main compo node preview render computations are now outside of mutex lock, so better for multithreading. * Tex node outputs did not work in some files loaded from 2.4. * Change RNA updates to take into account groups that may be shared between multiple node trees. --- source/blender/blenkernel/intern/node.c | 7 +- source/blender/editors/include/ED_node.h | 3 +- source/blender/editors/space_node/drawnode.c | 18 +++- source/blender/editors/space_node/node_draw.c | 47 +++++----- source/blender/editors/space_node/node_edit.c | 85 ++++++++++++------- .../blender/editors/space_node/node_intern.h | 3 +- .../editors/space_view3d/view3d_draw.c | 2 + source/blender/editors/transform/transform.c | 2 +- source/blender/makesdna/DNA_node_types.h | 2 +- source/blender/makesrna/intern/rna_nodetree.c | 35 +++++++- .../blender/nodes/intern/CMP_nodes/CMP_blur.c | 2 +- .../nodes/intern/CMP_nodes/CMP_channelMatte.c | 2 +- .../nodes/intern/CMP_nodes/CMP_chromaMatte.c | 2 +- .../nodes/intern/CMP_nodes/CMP_colorMatte.c | 2 +- .../nodes/intern/CMP_nodes/CMP_composite.c | 4 +- .../nodes/intern/CMP_nodes/CMP_diffMatte.c | 2 +- .../intern/CMP_nodes/CMP_distanceMatte.c | 2 +- .../nodes/intern/CMP_nodes/CMP_filter.c | 2 +- .../nodes/intern/CMP_nodes/CMP_image.c | 4 +- .../nodes/intern/CMP_nodes/CMP_levels.c | 2 +- .../nodes/intern/CMP_nodes/CMP_lummaMatte.c | 2 +- .../nodes/intern/CMP_nodes/CMP_mixrgb.c | 2 +- .../nodes/intern/CMP_nodes/CMP_outputFile.c | 2 +- .../nodes/intern/CMP_nodes/CMP_splitViewer.c | 2 +- .../nodes/intern/CMP_nodes/CMP_texture.c | 2 +- .../nodes/intern/CMP_nodes/CMP_viewer.c | 4 +- source/blender/nodes/intern/CMP_util.c | 39 ++++++--- source/blender/nodes/intern/CMP_util.h | 2 +- .../nodes/intern/TEX_nodes/TEX_output.c | 29 ++++--- source/blender/nodes/intern/TEX_util.c | 4 - 30 files changed, 205 insertions(+), 111 deletions(-) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index fad866a7201..1a89de7e8d6 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1246,9 +1246,12 @@ void nodeAddToPreview(bNode *node, float *col, int x, int y) if(preview) { if(x>=0 && y>=0) { if(xxsize && yysize) { - float *tar= preview->rect+ 4*((preview->xsize*y) + x); + unsigned char *tar= preview->rect+ 4*((preview->xsize*y) + x); //if(tar[0]==0.0f) { - QUATCOPY(tar, col); + tar[0]= FTOCHAR(col[0]); + tar[1]= FTOCHAR(col[1]); + tar[2]= FTOCHAR(col[2]); + tar[3]= FTOCHAR(col[3]); //} } //else printf("prv out bound x y %d %d\n", x, y); diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 305b2a64ffe..667a4ecb144 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -33,12 +33,13 @@ struct Scene; struct Tex; struct bContext; struct bNode; +struct ID; /* drawnode.c */ void ED_init_node_butfuncs(void); /* node_draw.c */ -void ED_node_changed_update(struct bContext *C, struct bNode *node); +void ED_node_changed_update(struct ID *id, struct bNode *node); /* node_edit.c */ void ED_node_shader_default(struct Material *ma); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index b8da42079c4..33be0b83f20 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -89,6 +89,7 @@ #include "UI_resources.h" #include "RE_pipeline.h" +#include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "node_intern.h" @@ -2106,12 +2107,13 @@ void node_rename_but(char *s) #endif -void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode) +void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage) { if((snode->flag & SNODE_BACKDRAW) && snode->treetype==NTREE_COMPOSIT) { Image *ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); + void *lock; + ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock); if(ibuf) { float x, y; @@ -2126,13 +2128,21 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode) x = (ar->winx-ibuf->x)/2 + snode->xof; y = (ar->winy-ibuf->y)/2 + snode->yof; + if(!ibuf->rect) { + if(color_manage) + ibuf->profile= IB_PROFILE_SRGB; + else + ibuf->profile = IB_PROFILE_NONE; + IMB_rect_from_float(ibuf); + } + if(ibuf->rect) glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect); - else if(ibuf->channels==4) - glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_FLOAT, ibuf->rect_float); wmPopMatrix(); } + + BKE_image_release_ibuf(ima, lock); } } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index dd2dc0d796a..26601958c8a 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -95,19 +95,19 @@ extern void ui_dropshadow(rctf *rct, float radius, float aspect, int select); extern void gl_round_box(int mode, float minx, float miny, float maxx, float maxy, float rad); extern void ui_draw_tria_icon(float x, float y, float aspect, char dir); -void ED_node_changed_update(bContext *C, bNode *node) +void ED_node_changed_update(ID *id, bNode *node) { - SpaceNode *snode= CTX_wm_space_node(C); + bNodeTree *nodetree, *edittree; + int treetype; - if(!snode) - return; + node_tree_from_ID(id, &nodetree, &edittree, &treetype); - if(snode->treetype==NTREE_SHADER) { - DAG_id_flush_update(snode->id, 0); - WM_event_add_notifier(C, NC_MATERIAL|ND_SHADING, snode->id); + if(treetype==NTREE_SHADER) { + DAG_id_flush_update(id, 0); + WM_main_add_notifier(NC_MATERIAL|ND_SHADING, id); } - else if(snode->treetype==NTREE_COMPOSIT) { - NodeTagChanged(snode->edittree, node); + else if(treetype==NTREE_COMPOSIT) { + NodeTagChanged(edittree, node); /* don't use NodeTagIDChanged, it gives far too many recomposites for image, scene layers, ... */ /* not the best implementation of the world... but we need it to work now :) */ @@ -122,23 +122,26 @@ void ED_node_changed_update(bContext *C, bNode *node) //addqueue(curarea->win, UI_BUT_EVENT, B_NODE_TREE_EXEC); } else { - node= node_tree_get_editgroup(snode->nodetree); + node= node_tree_get_editgroup(nodetree); if(node) - NodeTagIDChanged(snode->nodetree, node->id); + NodeTagIDChanged(nodetree, node->id); } - WM_event_add_notifier(C, NC_SCENE|ND_NODES, CTX_data_scene(C)); - } - else if(snode->treetype==NTREE_TEXTURE) { - DAG_id_flush_update(snode->id, 0); - WM_event_add_notifier(C, NC_TEXTURE|ND_NODES, snode->id); - } + WM_main_add_notifier(NC_SCENE|ND_NODES, id); + } + else if(treetype==NTREE_TEXTURE) { + DAG_id_flush_update(id, 0); + WM_main_add_notifier(NC_TEXTURE|ND_NODES, id); + } } static void do_node_internal_buttons(bContext *C, void *node_v, int event) { - if(event==B_NODE_EXEC) - ED_node_changed_update(C, node_v); + if(event==B_NODE_EXEC) { + SpaceNode *snode= CTX_wm_space_node(C); + if(snode && snode->id) + ED_node_changed_update(snode->id, node_v); + } } @@ -648,7 +651,7 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */ glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_FLOAT, preview->rect); + glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glDisable(GL_BLEND); @@ -1075,6 +1078,8 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) float col[3]; View2DScrollers *scrollers; SpaceNode *snode= CTX_wm_space_node(C); + Scene *scene= CTX_data_scene(C); + int color_manage = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT; UI_GetThemeColor3fv(TH_BACK, col); glClearColor(col[0], col[1], col[2], 0); @@ -1094,7 +1099,7 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d) UI_view2d_constant_grid_draw(C, v2d); /* backdrop */ - draw_nodespace_back_pix(ar, snode); + draw_nodespace_back_pix(ar, snode, color_manage); /* nodes */ snode_set_context(snode, CTX_data_scene(C)); diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 50a99650ec0..cee90b5a148 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -62,8 +62,6 @@ #include "BKE_scene.h" #include "BKE_utildefines.h" -#include "ED_render.h" - #include "BIF_gl.h" #include "BLI_arithb.h" @@ -74,8 +72,10 @@ #include "IMB_imbuf_types.h" -#include "ED_space_api.h" +#include "ED_node.h" +#include "ED_render.h" #include "ED_screen.h" +#include "ED_space_api.h" #include "ED_transform.h" #include "ED_types.h" @@ -581,13 +581,45 @@ void ED_node_texture_default(Tex *tx) ntreeSolveOrder(tx->nodetree); /* needed for pointers */ } +void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype) +{ + bNode *node; + short idtype= GS(id->name); + + if(idtype == ID_MA) { + *ntree= ((Material*)id)->nodetree; + if(treetype) *treetype= NTREE_SHADER; + } + else if(idtype == ID_SCE) { + *ntree= ((Scene*)id)->nodetree; + if(treetype) *treetype= NTREE_COMPOSIT; + } + else if(idtype == ID_TE) { + *ntree= ((Tex*)id)->nodetree; + if(treetype) *treetype= NTREE_TEXTURE; + } + + /* find editable group */ + if(edittree) { + if(*ntree) + for(node= (*ntree)->nodes.first; node; node= node->next) + if(node->flag & NODE_GROUP_EDIT) + break; + + if(node && node->id) + *edittree= (bNodeTree *)node->id; + else + *edittree= *ntree; + } +} + /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ void snode_set_context(SpaceNode *snode, Scene *scene) { Object *ob= OBACT; - bNode *node= NULL; snode->nodetree= NULL; + snode->edittree= NULL; snode->id= snode->from= NULL; if(snode->treetype==NTREE_SHADER) { @@ -597,7 +629,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene) if(ma) { snode->from= &ob->id; snode->id= &ma->id; - snode->nodetree= ma->nodetree; } } } @@ -608,8 +639,6 @@ void snode_set_context(SpaceNode *snode, Scene *scene) /* bit clumsy but reliable way to see if we draw first time */ if(snode->nodetree==NULL) ntreeCompositForceHidden(scene->nodetree, scene); - - snode->nodetree= scene->nodetree; } else if(snode->treetype==NTREE_TEXTURE) { Tex *tx= NULL; @@ -648,22 +677,11 @@ void snode_set_context(SpaceNode *snode, Scene *scene) tx= mtex->tex; } - if(tx) { - snode->id= &tx->id; - snode->nodetree= tx->nodetree; - } + snode->id= &tx->id; } - - /* find editable group */ - if(snode->nodetree) - for(node= snode->nodetree->nodes.first; node; node= node->next) - if(node->flag & NODE_GROUP_EDIT) - break; - - if(node && node->id) - snode->edittree= (bNodeTree *)node->id; - else - snode->edittree= snode->nodetree; + + if(snode->id) + node_tree_from_ID(snode->id, &snode->nodetree, &snode->edittree, NULL); } #if 0 @@ -691,15 +709,13 @@ static void node_active_image(Image *ima) void node_set_active(SpaceNode *snode, bNode *node) { - nodeSetActive(snode->edittree, node); - #if 0 - // XXX if(node->type!=NODE_GROUP) { - /* tree specific activate calls */ if(snode->treetype==NTREE_SHADER) { + // XXX +#if 0 /* when we select a material, active texture is cleared, for buttons */ if(node->id && GS(node->id->name)==ID_MA) @@ -709,8 +725,11 @@ void node_set_active(SpaceNode *snode, bNode *node) // allqueue(REDRAWBUTSSHADING, 1); // allqueue(REDRAWIPO, 0); +#endif } else if(snode->treetype==NTREE_COMPOSIT) { + Scene *scene= (Scene*)snode->id; + /* make active viewer, currently only 1 supported... */ if( ELEM(node->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { bNode *tnode; @@ -731,31 +750,37 @@ void node_set_active(SpaceNode *snode, bNode *node) if(gnode) NodeTagIDChanged(snode->nodetree, gnode->id); - // XXX snode_handle_recalc(snode); + ED_node_changed_update(snode->id, node); } /* addnode() doesnt link this yet... */ node->id= (ID *)BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node"); } else if(node->type==CMP_NODE_IMAGE) { + // XXX +#if 0 if(node->id) node_active_image((Image *)node->id); +#endif } else if(node->type==CMP_NODE_R_LAYERS) { - if(node->id==NULL || node->id==(ID *)G.scene) { - G.scene->r.actlay= node->custom1; + if(node->id==NULL || node->id==(ID *)scene) { + scene->r.actlay= node->custom1; + // XXX // allqueue(REDRAWBUTSSCENE, 0); } } } else if(snode->treetype==NTREE_TEXTURE) { + // XXX +#if 0 if(node->id) ; // XXX BIF_preview_changed(-1); // allqueue(REDRAWBUTSSHADING, 1); // allqueue(REDRAWIPO, 0); +#endif } } - #endif /* 0 */ } /* ***************** Edit Group operator ************* */ diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 2a929472c68..9f28a5e3dcb 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -69,9 +69,10 @@ void NODE_OT_select_border(struct wmOperatorType *ot); void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link); void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int th_col2, int do_shaded); int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol); -void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode); +void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage); /* node_edit.c */ +void node_tree_from_ID(ID *id, bNodeTree **ntree, bNodeTree **edittree, int *treetype); void snode_handle_recalc(bContext *C, SpaceNode *snode); bNode *next_node(bNodeTree *ntree); bNode *node_add_node(SpaceNode *snode, Scene *scene, int type, float locx, float locy); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 5612e60e899..06d0832cb8b 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1961,6 +1961,8 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar) v3d->zbuf= TRUE; glEnable(GL_DEPTH_TEST); } + else + v3d->zbuf= FALSE; // needs to be done always, gridview is adjusted in drawgrid() now v3d->gridview= v3d->grid; diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index b5920210381..839c3543515 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -322,7 +322,7 @@ static void viewRedrawForce(bContext *C, TransInfo *t) else if(t->spacetype == SPACE_NODE) { //ED_area_tag_redraw(t->sa); - WM_event_add_notifier(C, NC_SCENE|ND_NODES, NULL); + WM_event_add_notifier(C, NC_SPACE|ND_SPACE_NODE, NULL); } else if(t->spacetype == SPACE_SEQ) { diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index e70221df9ab..ba1bb66c901 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -99,7 +99,7 @@ typedef struct bNodeSocket { # # typedef struct bNodePreview { - float *rect; + unsigned char *rect; short xsize, ysize; } bNodePreview; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index ebd032bb0b1..4547362e235 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -31,10 +31,12 @@ #include "rna_internal.h" +#include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" #include "DNA_texture_types.h" +#include "BKE_main.h" #include "BKE_node.h" #include "BKE_image.h" @@ -140,11 +142,42 @@ static char *rna_Node_path(PointerRNA *ptr) return BLI_sprintfN("nodes[%d]", index); } +static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup) +{ + bNode *node; + + if(ntree == lookup) + return 1; + + for(node=ntree->nodes.first; node; node=node->next) + if(node->type == NODE_GROUP && node->id) + if(has_nodetree((bNodeTree*)node->id, lookup)) + return 1; + + return 0; +} + static void rna_Node_update(bContext *C, PointerRNA *ptr) { + Main *bmain= CTX_data_main(C); + bNodeTree *ntree= (bNodeTree*)ptr->id.data; bNode *node= (bNode*)ptr->data; + Material *ma; + Tex *tex; + Scene *sce; - ED_node_changed_update(C, node); + /* look through all datablocks, to support groups */ + for(ma=bmain->mat.first; ma; ma=ma->id.next) + if(ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree)) + ED_node_changed_update(&ma->id, node); + + for(tex=bmain->tex.first; tex; tex=tex->id.next) + if(tex->nodetree && tex->use_nodes && has_nodetree(tex->nodetree, ntree)) + ED_node_changed_update(&tex->id, node); + + for(sce=bmain->scene.first; sce; sce=sce->id.next) + if(sce->nodetree && sce->use_nodes && has_nodetree(sce->nodetree, ntree)) + ED_node_changed_update(&sce->id, node); } static void rna_Node_update_name(bContext *C, PointerRNA *ptr) diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_blur.c b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c index a96f3489978..68ccb04581b 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_blur.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_blur.c @@ -671,7 +671,7 @@ static void node_composit_exec_blur(void *data, bNode *node, bNodeStack **in, bN free_compbuf(img); } - generate_preview(node, out[0]->data); + generate_preview(data, node, out[0]->data); } static void node_composit_init_blur(bNode* node) diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c index b0a2531ac1f..ac940d76ed6 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_channelMatte.c @@ -166,7 +166,7 @@ static void node_composit_exec_channel_matte(void *data, bNode *node, bNodeStack break; } - generate_preview(node, outbuf); + generate_preview(data, node, outbuf); out[0]->data=outbuf; if(out[1]->hasoutput) out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c index 28b81fe9f47..c8cbe4538c5 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_chromaMatte.c @@ -154,7 +154,7 @@ static void node_composit_exec_chroma_matte(void *data, bNode *node, bNodeStack if(out[1]->hasoutput) out[1]->data= valbuf_from_rgbabuf(chromabuf, CHAN_A); - generate_preview(node, chromabuf); + generate_preview(data, node, chromabuf); if(cbuf!=in[0]->data) free_compbuf(cbuf); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_colorMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_colorMatte.c index 470d04d9dcc..e1fa4d78b96 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_colorMatte.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_colorMatte.c @@ -95,7 +95,7 @@ static void node_composit_exec_color_matte(void *data, bNode *node, bNodeStack * if(out[1]->hasoutput) out[1]->data= valbuf_from_rgbabuf(colorbuf, CHAN_A); - generate_preview(node, colorbuf); + generate_preview(data, node, colorbuf); if(cbuf!=in[0]->data) free_compbuf(cbuf); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_composite.c b/source/blender/nodes/intern/CMP_nodes/CMP_composite.c index 800cccc2bfc..d117a3cb235 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_composite.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_composite.c @@ -73,7 +73,7 @@ static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **i zbuf->malloc= 0; free_compbuf(zbuf); } - generate_preview(node, outbuf); + generate_preview(data, node, outbuf); /* we give outbuf to rr... */ rr->rectf= outbuf->rect; @@ -91,7 +91,7 @@ static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **i } } if(in[0]->data) - generate_preview(node, in[0]->data); + generate_preview(data, node, in[0]->data); } bNodeType cmp_node_composite= { diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c index 68a1bcd5471..d36d586211b 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_diffMatte.c @@ -108,7 +108,7 @@ static void node_composit_exec_diff_matte(void *data, bNode *node, bNodeStack ** out[0]->data=outbuf; if(out[1]->hasoutput) out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A); - generate_preview(node, outbuf); + generate_preview(data, node, outbuf); if(imbuf1!=in[0]->data) free_compbuf(imbuf1); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_distanceMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_distanceMatte.c index f24aedd6661..27b1ac1e181 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_distanceMatte.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_distanceMatte.c @@ -111,7 +111,7 @@ static void node_composit_exec_distance_matte(void *data, bNode *node, bNodeStac out[0]->data=workbuf; if(out[1]->hasoutput) out[1]->data=valbuf_from_rgbabuf(workbuf, CHAN_A); - generate_preview(node, workbuf); + generate_preview(data, node, workbuf); if(inbuf!=in[0]->data) free_compbuf(inbuf); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_filter.c b/source/blender/nodes/intern/CMP_nodes/CMP_filter.c index 2c3b78e13a3..8300c791698 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_filter.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_filter.c @@ -212,7 +212,7 @@ static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, out[0]->data= stackbuf; - generate_preview(node, out[0]->data); + generate_preview(data, node, out[0]->data); } } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_image.c b/source/blender/nodes/intern/CMP_nodes/CMP_image.c index 00be52a81aa..5e22f5cf016 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_image.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_image.c @@ -254,7 +254,7 @@ static void node_composit_exec_image(void *data, bNode *node, bNodeStack **in, b if(out[1]->hasoutput) out[1]->data= valbuf_from_rgbabuf(stackbuf, CHAN_A); - generate_preview(node, stackbuf); + generate_preview(data, node, stackbuf); } } }; @@ -386,7 +386,7 @@ static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **in, node_composit_rlayers_out(rd, rl, out, rr->rectx, rr->recty); - generate_preview(node, stackbuf); + generate_preview(data, node, stackbuf); } } } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_levels.c b/source/blender/nodes/intern/CMP_nodes/CMP_levels.c index 6056e9a28f4..f0e314793ed 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_levels.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_levels.c @@ -305,7 +305,7 @@ static void node_composit_exec_view_levels(void *data, bNode *node, bNodeStack * if(out[1]->hasoutput) out[1]->vec[0]= std_dev; - generate_preview(node, histogram); + generate_preview(data, node, histogram); if(cbuf!=in[0]->data) free_compbuf(cbuf); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c b/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c index 350def76736..3e284cd5ed1 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_lummaMatte.c @@ -87,7 +87,7 @@ static void node_composit_exec_luma_matte(void *data, bNode *node, bNodeStack ** composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_luma_matte, CB_RGBA); composit1_pixel_processor(node, outbuf, outbuf, in[1]->vec, do_yuva_to_rgba, CB_RGBA); - generate_preview(node, outbuf); + generate_preview(data, node, outbuf); out[0]->data=outbuf; if (out[1]->hasoutput) out[1]->data=valbuf_from_rgbabuf(outbuf, CHAN_A); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c index ca6de027b1d..25bb82b4a9f 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_mixrgb.c @@ -74,7 +74,7 @@ static void node_composit_exec_mix_rgb(void *data, bNode *node, bNodeStack **in, out[0]->data= stackbuf; - generate_preview(node, out[0]->data); + generate_preview(data, node, out[0]->data); } } diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c b/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c index 8c63c348b57..e63e5802507 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_outputFile.c @@ -71,7 +71,7 @@ static void node_composit_exec_output_file(void *data, bNode *node, bNodeStack * IMB_freeImBuf(ibuf); - generate_preview(node, cbuf); + generate_preview(data, node, cbuf); if(in[0]->data != cbuf) free_compbuf(cbuf); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c b/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c index 8ce5a7caa04..04383f478e9 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_splitViewer.c @@ -121,7 +121,7 @@ static void node_composit_exec_splitviewer(void *data, bNode *node, bNodeStack * composit3_pixel_processor(node, cbuf, buf1, in[0]->vec, buf2, in[1]->vec, mask, NULL, do_copy_split_rgba, CB_RGBA, CB_RGBA, CB_VAL); - generate_preview(node, cbuf); + generate_preview(data, node, cbuf); free_compbuf(cbuf); free_compbuf(mask); diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_texture.c b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c index b4d04076032..26e734579e3 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_texture.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_texture.c @@ -105,7 +105,7 @@ static void node_composit_exec_texture(void *data, bNode *node, bNodeStack **in, VECCOPY(prevbuf->procedural_size, in[1]->vec); prevbuf->procedural_type= CB_RGBA; composit1_pixel_processor(node, prevbuf, prevbuf, out[0]->vec, do_copy_rgba, CB_RGBA); - generate_preview(node, prevbuf); + generate_preview(data, node, prevbuf); free_compbuf(prevbuf); if(out[0]->hasoutput) { diff --git a/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c b/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c index c9e95e768c1..d0dcc5c6973 100644 --- a/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c +++ b/source/blender/nodes/intern/CMP_nodes/CMP_viewer.c @@ -106,12 +106,12 @@ static void node_composit_exec_viewer(void *data, bNode *node, bNodeStack **in, free_compbuf(zbuf); } - generate_preview(node, cbuf); + generate_preview(data, node, cbuf); free_compbuf(cbuf); } else if(in[0]->data) { - generate_preview(node, in[0]->data); + generate_preview(data, node, in[0]->data); } } diff --git a/source/blender/nodes/intern/CMP_util.c b/source/blender/nodes/intern/CMP_util.c index 075eefb4368..175a0a54371 100644 --- a/source/blender/nodes/intern/CMP_util.c +++ b/source/blender/nodes/intern/CMP_util.c @@ -604,9 +604,13 @@ static CompBuf *generate_procedural_preview(CompBuf *cbuf, int newx, int newy) return outbuf; } -void generate_preview(bNode *node, CompBuf *stackbuf) +void generate_preview(void *data, bNode *node, CompBuf *stackbuf) { + RenderData *rd= data; bNodePreview *preview= node->preview; + int xsize, ysize; + int color_manage= rd->color_mgt_flag & R_COLOR_MANAGEMENT; + unsigned char *rect; if(preview && stackbuf) { CompBuf *cbuf, *stackbuf_use; @@ -615,30 +619,41 @@ void generate_preview(bNode *node, CompBuf *stackbuf) stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA); - BLI_lock_thread(LOCK_PREVIEW); - if(stackbuf->x > stackbuf->y) { - preview->xsize= 140; - preview->ysize= (140*stackbuf->y)/stackbuf->x; + xsize= 140; + ysize= (140*stackbuf->y)/stackbuf->x; } else { - preview->ysize= 140; - preview->xsize= (140*stackbuf->x)/stackbuf->y; + ysize= 140; + xsize= (140*stackbuf->x)/stackbuf->y; } if(stackbuf_use->rect_procedural) - cbuf= generate_procedural_preview(stackbuf_use, preview->xsize, preview->ysize); + cbuf= generate_procedural_preview(stackbuf_use, xsize, ysize); else - cbuf= scalefast_compbuf(stackbuf_use, preview->xsize, preview->ysize); + cbuf= scalefast_compbuf(stackbuf_use, xsize, ysize); - /* this ensures free-compbuf does the right stuff */ - SWAP(float *, cbuf->rect, node->preview->rect); + /* convert to byte for preview */ + rect= MEM_callocN(sizeof(unsigned char)*4*xsize*ysize, "bNodePreview.rect"); - BLI_unlock_thread(LOCK_PREVIEW); + if(color_manage) + floatbuf_to_srgb_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize); + else + floatbuf_to_byte(cbuf->rect, rect, 0, xsize, 0, ysize, xsize); free_compbuf(cbuf); if(stackbuf_use!=stackbuf) free_compbuf(stackbuf_use); + + BLI_lock_thread(LOCK_PREVIEW); + + if(preview->rect) + MEM_freeN(preview->rect); + preview->xsize= xsize; + preview->ysize= ysize; + preview->rect= rect; + + BLI_unlock_thread(LOCK_PREVIEW); } } diff --git a/source/blender/nodes/intern/CMP_util.h b/source/blender/nodes/intern/CMP_util.h index 2a2dc97ed73..bb08a448bf4 100644 --- a/source/blender/nodes/intern/CMP_util.h +++ b/source/blender/nodes/intern/CMP_util.h @@ -141,7 +141,7 @@ void composit4_pixel_processor(bNode *node, CompBuf *out, CompBuf *src1_buf, flo int src1_type, int fac1_type, int src2_type, int fac2_type); CompBuf *valbuf_from_rgbabuf(CompBuf *cbuf, int channel); -void generate_preview(bNode *node, CompBuf *stackbuf); +void generate_preview(void *data, bNode *node, CompBuf *stackbuf); void do_copy_rgba(bNode *node, float *out, float *in); void do_copy_rgb(bNode *node, float *out, float *in); diff --git a/source/blender/nodes/intern/TEX_nodes/TEX_output.c b/source/blender/nodes/intern/TEX_nodes/TEX_output.c index 140c31a7986..580b4cde8bf 100644 --- a/source/blender/nodes/intern/TEX_nodes/TEX_output.c +++ b/source/blender/nodes/intern/TEX_nodes/TEX_output.c @@ -93,20 +93,23 @@ static void exec(void *data, bNode *node, bNodeStack **in, bNodeStack **out) tex_input_rgba(&target->tr, in[0], ¶ms, cdata->thread); tex_do_preview(node, params.coord, &target->tr); } - else if(cdata->which_output == node->custom1) { - TexParams params; - params_from_cdata(¶ms, cdata); + else { + /* 0 means don't care, so just use first */ + if(cdata->which_output == node->custom1 || (cdata->which_output == 0 && node->custom1 == 1)) { + TexParams params; + params_from_cdata(¶ms, cdata); + + osa(tex_input_rgba, &target->tr, in[0], ¶ms, cdata->thread); - osa(tex_input_rgba, &target->tr, in[0], ¶ms, cdata->thread); - - target->tin = (target->tr + target->tg + target->tb) / 3.0f; - target->talpha = 1.0f; - - if(target->nor) { - if(in[1]->hasinput) - osa(tex_input_vec, target->nor, in[1], ¶ms, cdata->thread); - else - target->nor = 0; + target->tin = (target->tr + target->tg + target->tb) / 3.0f; + target->talpha = 1.0f; + + if(target->nor) { + if(in[1]->hasinput) + osa(tex_input_vec, target->nor, in[1], ¶ms, cdata->thread); + else + target->nor = 0; + } } } } diff --git a/source/blender/nodes/intern/TEX_util.c b/source/blender/nodes/intern/TEX_util.c index 867bbd8c14e..8b247688e8c 100644 --- a/source/blender/nodes/intern/TEX_util.c +++ b/source/blender/nodes/intern/TEX_util.c @@ -176,10 +176,6 @@ void ntreeTexExecTree( TexResult dummy_texres; TexCallData data; - /* 0 means don't care, so just use first */ - if(which_output == 0) - which_output = 1; - if(!texres) texres = &dummy_texres; data.coord = coord; data.dxt = dxt; From 475ab5ceb4875eb37dd761f7a71ff569dd493395 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 8 Oct 2009 00:57:00 +0000 Subject: [PATCH 022/138] Rotation Modes Bugfix: Animating rotations using different rotation modes should now work more often than before. Previously, quaternion and axis-angle values were stored in the same variable in DNA, but that was causing problems with other animation curves overwriting the values and causing the rotations to not work as expected. There are still some issues, but I'll track those down later tonight --- source/blender/blenkernel/BKE_armature.h | 2 +- source/blender/blenkernel/intern/action.c | 10 ++-- source/blender/blenkernel/intern/armature.c | 28 ++++------- source/blender/blenkernel/intern/object.c | 8 +-- .../editors/animation/keyframes_general.c | 1 + .../blender/editors/armature/editarmature.c | 49 +++++++++++++----- source/blender/editors/armature/poseobject.c | 14 +++--- .../blender/editors/object/object_transform.c | 50 ++++++++++++++----- .../editors/space_view3d/view3d_buttons.c | 4 +- .../editors/transform/transform_conversions.c | 4 +- source/blender/makesdna/DNA_action_types.h | 11 ++-- source/blender/makesdna/DNA_object_types.h | 6 ++- source/blender/makesrna/intern/rna_object.c | 30 +++++++++-- source/blender/makesrna/intern/rna_pose.c | 32 ++++++++++-- 14 files changed, 172 insertions(+), 77 deletions(-) diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index e5d0c4274b3..8f109034e3e 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -104,7 +104,7 @@ void armature_loc_pose_to_bone(struct bPoseChannel *pchan, float *inloc, float * void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float arm_mat[][4]); /* Rotation Mode Conversions - Used for PoseChannels + Objects... */ -void BKE_rotMode_change_values(float quat[4], float eul[3], short oldMode, short newMode); +void BKE_rotMode_change_values(float quat[4], float eul[3], float axis[3], float *angle, short oldMode, short newMode); /* B-Bone support */ typedef struct Mat4 { diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 7be763eae9d..25f539a1992 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -446,7 +446,7 @@ bPoseChannel *verify_pose_channel(bPose* pose, const char* name) strncpy(chan->name, name, 31); /* init vars to prevent math errors */ - chan->quat[0] = 1.0f; + chan->quat[0] = chan->rotAxis[1]= 1.0f; chan->size[0] = chan->size[1] = chan->size[2] = 1.0f; chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f; @@ -607,6 +607,8 @@ static void copy_pose_channel_data(bPoseChannel *pchan, const bPoseChannel *chan VECCOPY(pchan->loc, chan->loc); VECCOPY(pchan->size, chan->size); VECCOPY(pchan->eul, chan->eul); + VECCOPY(pchan->rotAxis, chan->rotAxis); + pchan->rotAngle= chan->rotAngle; QUATCOPY(pchan->quat, chan->quat); pchan->rotmode= chan->rotmode; Mat4CpyMat4(pchan->chan_mat, (float(*)[4])chan->chan_mat); @@ -975,14 +977,16 @@ void rest_pose(bPose *pose) memset(pose->stride_offset, 0, sizeof(pose->stride_offset)); memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset)); - for (pchan=pose->chanbase.first; pchan; pchan= pchan->next){ + for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) { for (i=0; i<3; i++) { pchan->loc[i]= 0.0f; pchan->quat[i+1]= 0.0f; pchan->eul[i]= 0.0f; pchan->size[i]= 1.0f; + pchan->rotAxis[i]= 0.0f; } - pchan->quat[0]= 1.0f; + pchan->quat[0]= pchan->rotAxis[1]= 1.0f; + pchan->rotAngle= 0.0f; pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE); } diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 6220835a620..a0abe780273 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1285,16 +1285,14 @@ void armature_mat_pose_to_delta(float delta_mat[][4], float pose_mat[][4], float /* Called from RNA when rotation mode changes * - the result should be that the rotations given in the provided pointers have had conversions * applied (as appropriate), such that the rotation of the element hasn't 'visually' changed - * - * - as in SDNA data, quat is used to store quaternions AND axis-angle rotations... */ -void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, short newMode) +void BKE_rotMode_change_values (float quat[4], float eul[3], float *axis, float angle[3], short oldMode, short newMode) { /* check if any change - if so, need to convert data */ if (newMode > 0) { /* to euler */ if (oldMode == ROT_MODE_AXISANGLE) { /* axis-angle to euler */ - AxisAngleToEulO(&quat[1], quat[0], eul, newMode); + AxisAngleToEulO(axis, *angle, eul, newMode); } else if (oldMode == ROT_MODE_QUAT) { /* quat to euler */ @@ -1305,11 +1303,7 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, shor else if (newMode == ROT_MODE_QUAT) { /* to quat */ if (oldMode == ROT_MODE_AXISANGLE) { /* axis angle to quat */ - float q[4]; - - /* copy to temp var first, since quats and axis-angle are stored in same place */ - QuatCopy(q, quat); - AxisAngleToQuat(q, &quat[1], quat[0]); + AxisAngleToQuat(quat, axis, *angle); } else if (oldMode > 0) { /* euler to quat */ @@ -1317,24 +1311,20 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], short oldMode, shor } /* else { no conversion needed } */ } - else { /* to axis-angle */ + else if (newMode == ROT_MODE_AXISANGLE) { /* to axis-angle */ if (oldMode > 0) { /* euler to axis angle */ EulOToAxisAngle(eul, oldMode, &quat[1], &quat[0]); } else if (oldMode == ROT_MODE_QUAT) { /* quat to axis angle */ - float q[4]; - - /* copy to temp var first, since quats and axis-angle are stored in same place */ - QuatCopy(q, quat); - QuatToAxisAngle(q, &quat[1], &quat[0]); + QuatToAxisAngle(quat, axis, angle); } /* when converting to axis-angle, we need a special exception for the case when there is no axis */ - if (IS_EQ(quat[1], quat[2]) && IS_EQ(quat[2], quat[3])) { + if (IS_EQ(axis[0], axis[1]) && IS_EQ(axis[1], axis[2])) { /* for now, rotate around y-axis then (so that it simply becomes the roll) */ - quat[2]= 1.0f; + axis[1]= 1.0f; } } } @@ -1651,8 +1641,8 @@ void chan_calc_mat(bPoseChannel *chan) EulOToMat3(chan->eul, chan->rotmode, rmat); } else if (chan->rotmode == ROT_MODE_AXISANGLE) { - /* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */ - AxisAngleToMat3(&chan->quat[1], chan->quat[0], rmat); + /* axis-angle - not really that great for 3D-changing orientations */ + AxisAngleToMat3(chan->rotAxis, chan->rotAngle, rmat); } else { /* quats are normalised before use to eliminate scaling issues */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index ddf7e7ff4a3..89757533fb8 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1041,6 +1041,8 @@ Object *add_object(struct Scene *scene, int type) * but rotations default to quaternions */ ob->rotmode= ROT_MODE_EUL; + /* axis-angle must not have a 0,0,0 axis, so set y-axis as default... */ + ob->rotAxis[1]= ob->drotAxis[1]= 1.0f; base= scene_add_base(scene, ob); scene_select_base(scene, base); @@ -1602,9 +1604,9 @@ void object_rot_to_mat3(Object *ob, float mat[][3]) EulOToMat3(ob->drot, ob->rotmode, dmat); } else if (ob->rotmode == ROT_MODE_AXISANGLE) { - /* axis-angle - stored in quaternion data, but not really that great for 3D-changing orientations */ - AxisAngleToMat3(&ob->quat[1], ob->quat[0], rmat); - AxisAngleToMat3(&ob->dquat[1], ob->dquat[0], dmat); + /* axis-angle - not really that great for 3D-changing orientations */ + AxisAngleToMat3(ob->rotAxis, ob->rotAngle, rmat); + AxisAngleToMat3(ob->drotAxis, ob->drotAngle, dmat); } else { /* quats are normalised before use to eliminate scaling issues */ diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index f13d35c7d4a..3ad6ddf2c6f 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -581,6 +581,7 @@ short paste_animedit_keys (bAnimContext *ac, ListBase *anim_data) for (aci= animcopybuf.first; aci; aci= aci->next) { /* check that paths exist */ if (aci->rna_path && fcu->rna_path) { + // FIXME: this breaks for bone names! if (strcmp(aci->rna_path, fcu->rna_path) == 0) { /* should be a match unless there's more than one of these */ if ((no_name) || (aci->array_index == fcu->array_index)) diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c index c32837be420..0343fea5bfb 100644 --- a/source/blender/editors/armature/editarmature.c +++ b/source/blender/editors/armature/editarmature.c @@ -4875,14 +4875,39 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) /* check if convert to eulers for locking... */ if (pchan->protectflag & OB_LOCK_ROT4D) { /* perform clamping on a component by component basis */ - if ((pchan->protectflag & OB_LOCK_ROTW) == 0) - pchan->quat[0]= (pchan->rotmode == ROT_MODE_AXISANGLE) ? 0.0f : 1.0f; - if ((pchan->protectflag & OB_LOCK_ROTX) == 0) - pchan->quat[1]= 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTY) == 0) - pchan->quat[2]= 0.0f; - if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) - pchan->quat[3]= 0.0f; + if (pchan->rotmode == ROT_MODE_AXISANGLE) { + if ((pchan->protectflag & OB_LOCK_ROTW) == 0) + pchan->rotAngle= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTX) == 0) + pchan->rotAxis[0]= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTY) == 0) + pchan->rotAxis[1]= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) + pchan->rotAxis[2]= 0.0f; + + /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ + if (IS_EQ(pchan->rotAxis[0], pchan->rotAxis[1]) && IS_EQ(pchan->rotAxis[1], pchan->rotAxis[2])) + pchan->rotAxis[1] = 1.0f; + } + else if (pchan->rotmode == ROT_MODE_QUAT) { + if ((pchan->protectflag & OB_LOCK_ROTW) == 0) + pchan->quat[0]= 1.0f; + if ((pchan->protectflag & OB_LOCK_ROTX) == 0) + pchan->quat[1]= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTY) == 0) + pchan->quat[2]= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) + pchan->quat[3]= 0.0f; + } + else { + /* the flag may have been set for the other modes, so just ignore the extra flag... */ + if ((pchan->protectflag & OB_LOCK_ROTX) == 0) + pchan->eul[0]= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTY) == 0) + pchan->eul[1]= 0.0f; + if ((pchan->protectflag & OB_LOCK_ROTZ) == 0) + pchan->eul[2]= 0.0f; + } } else { /* perform clamping using euler form (3-components) */ @@ -4893,7 +4918,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) QuatToEul(pchan->quat, oldeul); } else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], oldeul, EULER_ORDER_DEFAULT); + AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, oldeul, EULER_ORDER_DEFAULT); } else { VECCOPY(oldeul, pchan->eul); @@ -4916,7 +4941,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) } } else if (pchan->rotmode == ROT_MODE_AXISANGLE) { - AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], oldeul, EULER_ORDER_DEFAULT); + EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle); } else { VECCOPY(pchan->eul, eul); @@ -4930,8 +4955,8 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op) } else if (pchan->rotmode == ROT_MODE_AXISANGLE) { /* by default, make rotation of 0 radians around y-axis (roll) */ - pchan->quat[0]=pchan->quat[1]=pchan->quat[3]= 0.0f; - pchan->quat[2]= 1.0f; + pchan->rotAxis[0]=pchan->rotAxis[2]=pchan->rotAngle= 0.0f; + pchan->rotAxis[1]= 1.0f; } else { pchan->eul[0]= pchan->eul[1]= pchan->eul[2]= 0.0f; diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index edbc7b9ae9b..461a70bbf86 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -819,7 +819,7 @@ void pose_copy_menu(Scene *scene) /* need to convert to quat first (in temp var)... */ Mat4ToQuat(delta_mat, tmp_quat); - QuatToAxisAngle(tmp_quat, &pchan->quat[1], &pchan->quat[0]); + QuatToAxisAngle(tmp_quat, pchan->rotAxis, &pchan->rotAngle); } else if (pchan->rotmode == ROT_MODE_QUAT) Mat4ToQuat(delta_mat, pchan->quat); @@ -1024,23 +1024,23 @@ static int pose_paste_exec (bContext *C, wmOperator *op) else if (pchan->rotmode > 0) { /* quat/axis-angle to euler */ if (chan->rotmode == ROT_MODE_AXISANGLE) - AxisAngleToEulO(&chan->quat[1], chan->quat[0], pchan->eul, pchan->rotmode); + AxisAngleToEulO(chan->rotAxis, chan->rotAngle, pchan->eul, pchan->rotmode); else QuatToEulO(chan->quat, pchan->eul, pchan->rotmode); } else if (pchan->rotmode == ROT_MODE_AXISANGLE) { /* quat/euler to axis angle */ if (chan->rotmode > 0) - EulOToAxisAngle(chan->eul, chan->rotmode, &pchan->quat[1], &pchan->quat[0]); + EulOToAxisAngle(chan->eul, chan->rotmode, pchan->rotAxis, &pchan->rotAngle); else - QuatToAxisAngle(chan->quat, &pchan->quat[1], &pchan->quat[0]); + QuatToAxisAngle(chan->quat, pchan->rotAxis, &pchan->rotAngle); } else { /* euler/axis-angle to quat */ if (chan->rotmode > 0) EulOToQuat(chan->eul, chan->rotmode, pchan->quat); else - AxisAngleToQuat(pchan->quat, &chan->quat[1], chan->quat[0]); + AxisAngleToQuat(pchan->quat, chan->rotAxis, pchan->rotAngle); } /* paste flipped pose? */ @@ -1055,10 +1055,10 @@ static int pose_paste_exec (bContext *C, wmOperator *op) else if (pchan->rotmode == ROT_MODE_AXISANGLE) { float eul[3]; - AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], eul, EULER_ORDER_DEFAULT); + AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, eul, EULER_ORDER_DEFAULT); eul[1]*= -1; eul[2]*= -1; - EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, &pchan->quat[1], &pchan->quat[0]); + EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle); // experimental method (uncomment to test): #if 0 diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index cd0d97eed44..898d541d09d 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -117,17 +117,41 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) { if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) { if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) { - /* check if convert to eulers for locking... */ if (ob->protectflag & OB_LOCK_ROT4D) { /* perform clamping on a component by component basis */ - if ((ob->protectflag & OB_LOCK_ROTW) == 0) - ob->quat[0]= (ob->rotmode == ROT_MODE_AXISANGLE) ? 0.0f : 1.0f; - if ((ob->protectflag & OB_LOCK_ROTX) == 0) - ob->quat[1]= 0.0f; - if ((ob->protectflag & OB_LOCK_ROTY) == 0) - ob->quat[2]= 0.0f; - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) - ob->quat[3]= 0.0f; + if (ob->rotmode == ROT_MODE_AXISANGLE) { + if ((ob->protectflag & OB_LOCK_ROTW) == 0) + ob->rotAngle= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTX) == 0) + ob->rotAxis[0]= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTY) == 0) + ob->rotAxis[1]= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) + ob->rotAxis[2]= 0.0f; + + /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ + if (IS_EQ(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQ(ob->rotAxis[1], ob->rotAxis[2])) + ob->rotAxis[1] = 1.0f; + } + else if (ob->rotmode == ROT_MODE_QUAT) { + if ((ob->protectflag & OB_LOCK_ROTW) == 0) + ob->quat[0]= 1.0f; + if ((ob->protectflag & OB_LOCK_ROTX) == 0) + ob->quat[1]= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTY) == 0) + ob->quat[2]= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) + ob->quat[3]= 0.0f; + } + else { + /* the flag may have been set for the other modes, so just ignore the extra flag... */ + if ((ob->protectflag & OB_LOCK_ROTX) == 0) + ob->rot[0]= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTY) == 0) + ob->rot[1]= 0.0f; + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) + ob->rot[2]= 0.0f; + } } else { /* perform clamping using euler form (3-components) */ @@ -138,7 +162,7 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op) QuatToEul(ob->quat, oldeul); } else if (ob->rotmode == ROT_MODE_AXISANGLE) { - AxisAngleToEulO(&ob->quat[1], ob->quat[0], oldeul, EULER_ORDER_DEFAULT); + AxisAngleToEulO(ob->rotAxis, ob->rotAngle, oldeul, EULER_ORDER_DEFAULT); } else { VECCOPY(oldeul, ob->rot); @@ -161,7 +185,7 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op) } } else if (ob->rotmode == ROT_MODE_AXISANGLE) { - AxisAngleToEulO(&ob->quat[1], ob->quat[0], oldeul, EULER_ORDER_DEFAULT); + EulOToAxisAngle(eul, EULER_ORDER_DEFAULT, ob->rotAxis, &ob->rotAngle); } else { VECCOPY(ob->rot, eul); @@ -175,8 +199,8 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op) } else if (ob->rotmode == ROT_MODE_AXISANGLE) { /* by default, make rotation of 0 radians around y-axis (roll) */ - ob->quat[0]=ob->quat[1]=ob->quat[3]= 0.0f; - ob->quat[2]= 1.0f; + ob->rotAxis[0]=ob->rotAxis[2]=ob->rotAngle= 0.0f; + ob->rotAxis[1]= 1.0f; } else { ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0f; diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index ec72d72013b..c2f5d736875 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -689,6 +689,7 @@ static void do_view3d_region_buttons(bContext *C, void *arg, int event) case B_OBJECTPANELROT: if(ob) { + // TODO: need to support roation modes ob->rot[0]= M_PI*tfp->ob_eul[0]/180.0; ob->rot[1]= M_PI*tfp->ob_eul[1]/180.0; ob->rot[2]= M_PI*tfp->ob_eul[2]/180.0; @@ -870,13 +871,12 @@ static void do_view3d_region_buttons(bContext *C, void *arg, int event) float quat[4]; /* convert to axis-angle, passing through quats */ EulToQuat(eul, quat); - QuatToAxisAngle(quat, &pchan->quat[1], &pchan->quat[0]); + QuatToAxisAngle(quat, pchan->rotAxis, &pchan->rotAngle); } else if (pchan->rotmode == ROT_MODE_QUAT) EulToQuat(eul, pchan->quat); else VecCopyf(pchan->eul, eul); - } /* no break, pass on */ case B_ARMATUREPANEL2: diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index f6d30a7bec9..1b11d43c200 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -509,7 +509,7 @@ static short apply_targetless_ik(Object *ob) if (parchan->rotmode > 0) Mat3ToEulO(rmat3, parchan->eul, parchan->rotmode); else if (parchan->rotmode == ROT_MODE_AXISANGLE) - Mat3ToAxisAngle(rmat3, &parchan->quat[1], &parchan->quat[0]); + Mat3ToAxisAngle(rmat3, parchan->rotAxis, &pchan->rotAngle); else Mat3ToQuat(rmat3, parchan->quat); @@ -519,7 +519,7 @@ static short apply_targetless_ik(Object *ob) if (parchan->rotmode > 0) EulOToMat3(parchan->eul, parchan->rotmode, qrmat); else if (parchan->rotmode == ROT_MODE_AXISANGLE) - AxisAngleToMat3(&parchan->quat[1], parchan->quat[0], qrmat); + AxisAngleToMat3(parchan->rotAxis, parchan->rotAngle, qrmat); else QuatToMat3(parchan->quat, qrmat); diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 3201a1df6a5..e2eb13f0bdf 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -128,12 +128,15 @@ typedef struct bPoseChannel { void *dual_quat; void *b_bone_dual_quats; - float loc[3]; /* transforms - written in by actions or transform */ + /* transforms - written in by actions or transform */ + float loc[3]; float size[3]; - float eul[3]; /* rotations - written in by actions or transform (but only euler/quat in use at any one time!) */ - float quat[4]; - short rotmode; /* for now either quat (0), or xyz-euler (1) */ + /* rotations - written in by actions or transform (but only one representation gets used at any time) */ + float eul[3]; /* euler rotation */ + float quat[4]; /* quaternion rotation */ + float rotAxis[3], rotAngle; /* axis-angle rotation */ + short rotmode; /* eRotationModes - rotation representation to use */ short pad; float chan_mat[4][4]; /* matrix result of loc/quat/size , and where we put deform in, see next line */ diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index ade22e4ebd4..0940a88267c 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -133,8 +133,10 @@ typedef struct Object { /* rot en drot have to be together! (transform('r' en 's')) */ float loc[3], dloc[3], orig[3]; float size[3], dsize[3]; - float rot[3], drot[3]; - float quat[4], dquat[4]; + float rot[3], drot[3]; /* euler rotation */ + float quat[4], dquat[4]; /* quaternion rotation */ + float rotAxis[3], drotAxis[3]; /* axis angle rotation - axis part */ + float rotAngle, drotAngle; /* axis angle rotation - angle part */ float obmat[4][4]; float parentinv[4][4]; /* inverse result of parent, so that object doesn't 'stick' to parent */ float constinv[4][4]; /* inverse result of constraints. doesn't include effect of parent or object local transform */ diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 4fb2db42b8b..3184ebc6db2 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -484,12 +484,34 @@ static void rna_Object_rotation_euler_set(PointerRNA *ptr, const float *value) VECCOPY(ob->rot, value); } +/* rotation - axis-angle */ +static void rna_Object_rotation_axis_angle_get(PointerRNA *ptr, float *value) +{ + Object *ob= ptr->data; + + /* for now, assume that rotation mode is axis-angle */ + value[0]= ob->rotAngle; + VecCopyf(&value[1], ob->rotAxis); +} + +/* rotation - axis-angle */ +static void rna_Object_rotation_axis_angle_set(PointerRNA *ptr, const float *value) +{ + Object *ob= ptr->data; + + /* for now, assume that rotation mode is axis-angle */ + ob->rotAngle= value[0]; + VecCopyf(ob->rotAxis, (float *)&value[1]); + + // TODO: validate axis? +} + static void rna_Object_rotation_mode_set(PointerRNA *ptr, int value) { Object *ob= ptr->data; /* use API Method for conversions... */ - BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotmode, (short)value); + BKE_rotMode_change_values(ob->quat, ob->rot, ob->rotAxis, &ob->rotAngle, ob->rotmode, (short)value); /* finally, set the new rotation type */ ob->rotmode= value; @@ -1242,8 +1264,8 @@ static void rna_def_object(BlenderRNA *brna) * having a single one is better for Keyframing and other property-management situations... */ prop= RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE); - RNA_def_property_float_sdna(prop, NULL, "quat"); - // TODO: we may need some validation funcs + RNA_def_property_array(prop, 4); // TODO: maybe we'll need to define the 'default value' getter too... + RNA_def_property_float_funcs(prop, "rna_Object_rotation_axis_angle_get", "rna_Object_rotation_axis_angle_set", NULL); RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation."); RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_update"); @@ -1283,7 +1305,7 @@ static void rna_def_object(BlenderRNA *brna) #if 0 // XXX not supported well yet... prop= RNA_def_property(srna, "delta_rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE); - RNA_def_property_float_sdna(prop, NULL, "dquat"); + RNA_def_property_float_sdna(prop, NULL, "dquat"); // FIXME: this is not a single field any more! (drotAxis and drotAngle) RNA_def_property_ui_text(prop, "Delta Rotation (Axis Angle)", "Extra added rotation to the rotation of the object (when using Axis-Angle rotations)."); RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_update"); #endif diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index ecb2dba0197..27069b361fd 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -162,7 +162,7 @@ static void rna_PoseChannel_rotation_euler_get(PointerRNA *ptr, float *value) bPoseChannel *pchan= ptr->data; if(pchan->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */ - AxisAngleToEulO(&pchan->quat[1], pchan->quat[0], value, EULER_ORDER_DEFAULT); + AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, value, EULER_ORDER_DEFAULT); else if(pchan->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */ QuatToEul(pchan->quat, value); else @@ -175,19 +175,41 @@ static void rna_PoseChannel_rotation_euler_set(PointerRNA *ptr, const float *val bPoseChannel *pchan= ptr->data; if(pchan->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */ - EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, &pchan->quat[1], &pchan->quat[0]); + EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle); else if(pchan->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */ EulToQuat((float*)value, pchan->quat); else VECCOPY(pchan->eul, value); } +/* rotation - axis-angle */ +static void rna_PoseChannel_rotation_axis_angle_get(PointerRNA *ptr, float *value) +{ + bPoseChannel *pchan= ptr->data; + + /* for now, assume that rotation mode is axis-angle */ + value[0]= pchan->rotAngle; + VecCopyf(&value[1], pchan->rotAxis); +} + +/* rotation - axis-angle */ +static void rna_PoseChannel_rotation_axis_angle_set(PointerRNA *ptr, const float *value) +{ + bPoseChannel *pchan= ptr->data; + + /* for now, assume that rotation mode is axis-angle */ + pchan->rotAngle= value[0]; + VecCopyf(pchan->rotAxis, (float *)&value[1]); + + // TODO: validate axis? +} + static void rna_PoseChannel_rotation_mode_set(PointerRNA *ptr, int value) { bPoseChannel *pchan= ptr->data; /* use API Method for conversions... */ - BKE_rotMode_change_values(pchan->quat, pchan->eul, pchan->rotmode, (short)value); + BKE_rotMode_change_values(pchan->quat, pchan->eul, pchan->rotAxis, &pchan->rotAngle, pchan->rotmode, (short)value); /* finally, set the new rotation type */ pchan->rotmode= value; @@ -578,8 +600,8 @@ static void rna_def_pose_channel(BlenderRNA *brna) * having a single one is better for Keyframing and other property-management situations... */ prop= RNA_def_property(srna, "rotation_axis_angle", PROP_FLOAT, PROP_AXISANGLE); - RNA_def_property_float_sdna(prop, NULL, "quat"); - // TODO: we may need some validation funcs + RNA_def_property_array(prop, 4); // TODO: maybe we'll need to define the 'default value' getter too... + RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_axis_angle_get", "rna_PoseChannel_rotation_axis_angle_set", NULL); RNA_def_property_ui_text(prop, "Axis-Angle Rotation", "Angle of Rotation for Axis-Angle rotation representation."); RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Pose_update"); From b4b031eae7569d5e08f034368417417d10da3a60 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 8 Oct 2009 05:02:04 +0000 Subject: [PATCH 023/138] Fixed remaining bugs with animating rotation modes: * Removed the hack-functions to set euler rotations from the values set in the other rotation representations, even when euler rotations weren't being used. I pressume that this was added for being able to represent quats in terms of eulers for the UI, but really it would break animation evaluation (i.e. euler curves after quaternion curves would always block the quaternion curves). * Object rotation values in the transform properties panel now take into account rotation modes, so the appropriate rotations will get converted to quaternions before being drawn. * Fixed a few bugs with some of the conversion code (minor stuff left out). --- source/blender/blenkernel/intern/armature.c | 2 +- .../editors/space_view3d/view3d_buttons.c | 40 +++++++++++++++---- source/blender/makesrna/intern/rna_object.c | 27 ------------- source/blender/makesrna/intern/rna_pose.c | 34 ++-------------- 4 files changed, 36 insertions(+), 67 deletions(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index a0abe780273..9894cc85784 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1314,7 +1314,7 @@ void BKE_rotMode_change_values (float quat[4], float eul[3], float *axis, float else if (newMode == ROT_MODE_AXISANGLE) { /* to axis-angle */ if (oldMode > 0) { /* euler to axis angle */ - EulOToAxisAngle(eul, oldMode, &quat[1], &quat[0]); + EulOToAxisAngle(eul, oldMode, axis, angle); } else if (oldMode == ROT_MODE_QUAT) { /* quat to axis angle */ diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index c2f5d736875..161b73032f5 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -520,7 +520,7 @@ static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float if (pchan->rotmode == ROT_MODE_AXISANGLE) { float quat[4]; /* convert to euler, passing through quats... */ - AxisAngleToQuat(quat, &pchan->quat[1], pchan->quat[0]); + AxisAngleToQuat(quat, pchan->rotAxis, pchan->rotAngle); QuatToEul(quat, tfp->ob_eul); } else if (pchan->rotmode == ROT_MODE_QUAT) @@ -689,10 +689,24 @@ static void do_view3d_region_buttons(bContext *C, void *arg, int event) case B_OBJECTPANELROT: if(ob) { - // TODO: need to support roation modes - ob->rot[0]= M_PI*tfp->ob_eul[0]/180.0; - ob->rot[1]= M_PI*tfp->ob_eul[1]/180.0; - ob->rot[2]= M_PI*tfp->ob_eul[2]/180.0; + float eul[3]; + + /* make a copy to eul[3], to allow TAB on buttons to work */ + eul[0]= M_PI*tfp->ob_eul[0]/180.0; + eul[1]= M_PI*tfp->ob_eul[1]/180.0; + eul[2]= M_PI*tfp->ob_eul[2]/180.0; + + if (ob->rotmode == ROT_MODE_AXISANGLE) { + float quat[4]; + /* convert to axis-angle, passing through quats */ + EulToQuat(eul, quat); + QuatToAxisAngle(quat, ob->rotAxis, &ob->rotAngle); + } + else if (ob->rotmode == ROT_MODE_QUAT) + EulToQuat(eul, ob->quat); + else + VecCopyf(ob->rot, eul); + DAG_id_flush_update(&ob->id, OB_RECALC_OB); } break; @@ -1130,9 +1144,19 @@ static void view3d_panel_object(const bContext *C, Panel *pa) uiDefIconButBitS(block, ICONTOG, OB_LOCK_LOCZ, B_REDR, ICON_UNLOCKED, 125, 240, 25, 19, &(ob->protectflag), 0, 0, 0, 0, "Protects Z Location value from being Transformed"); uiBlockEndAlign(block); - tfp->ob_eul[0]= 180.0*ob->rot[0]/M_PI; - tfp->ob_eul[1]= 180.0*ob->rot[1]/M_PI; - tfp->ob_eul[2]= 180.0*ob->rot[2]/M_PI; + if (ob->rotmode == ROT_MODE_AXISANGLE) { + float quat[4]; + /* convert to euler, passing through quats... */ + AxisAngleToQuat(quat, ob->rotAxis, ob->rotAngle); + QuatToEul(quat, tfp->ob_eul); + } + else if (ob->rotmode == ROT_MODE_QUAT) + QuatToEul(ob->quat, tfp->ob_eul); + else + VecCopyf(tfp->ob_eul, ob->rot); + tfp->ob_eul[0]*= 180.0/M_PI; + tfp->ob_eul[1]*= 180.0/M_PI; + tfp->ob_eul[2]*= 180.0/M_PI; uiBlockBeginAlign(block); if ((ob->parent) && (ob->partype == PARBONE)) { diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 3184ebc6db2..013d455b1b3 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -458,32 +458,6 @@ static void rna_Object_active_particle_system_index_set(struct PointerRNA *ptr, psys_set_current_num(ob, value); } -/* rotation - euler angles */ -static void rna_Object_rotation_euler_get(PointerRNA *ptr, float *value) -{ - Object *ob= ptr->data; - - if(ob->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */ - AxisAngleToEulO(&ob->quat[1], ob->quat[0], value, EULER_ORDER_DEFAULT); - else if(ob->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */ - QuatToEul(ob->quat, value); - else - VECCOPY(value, ob->rot); -} - -/* rotation - euler angles */ -static void rna_Object_rotation_euler_set(PointerRNA *ptr, const float *value) -{ - Object *ob= ptr->data; - - if(ob->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */ - EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, &ob->quat[1], &ob->quat[0]); - else if(ob->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */ - EulToQuat((float*)value, ob->quat); - else - VECCOPY(ob->rot, value); -} - /* rotation - axis-angle */ static void rna_Object_rotation_axis_angle_get(PointerRNA *ptr, float *value) { @@ -1271,7 +1245,6 @@ static void rna_def_object(BlenderRNA *brna) prop= RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "rot"); - RNA_def_property_float_funcs(prop, "rna_Object_rotation_euler_get", "rna_Object_rotation_euler_set", NULL); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers."); RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Object_update"); diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 27069b361fd..584c971951a 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -156,32 +156,6 @@ static void rna_Pose_ik_solver_update(bContext *C, PointerRNA *ptr) DAG_id_flush_update(&ob->id, OB_RECALC_DATA|OB_RECALC_OB); } -/* rotation - euler angles */ -static void rna_PoseChannel_rotation_euler_get(PointerRNA *ptr, float *value) -{ - bPoseChannel *pchan= ptr->data; - - if(pchan->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */ - AxisAngleToEulO(pchan->rotAxis, pchan->rotAngle, value, EULER_ORDER_DEFAULT); - else if(pchan->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */ - QuatToEul(pchan->quat, value); - else - VECCOPY(value, pchan->eul); -} - -/* rotation - euler angles */ -static void rna_PoseChannel_rotation_euler_set(PointerRNA *ptr, const float *value) -{ - bPoseChannel *pchan= ptr->data; - - if(pchan->rotmode == ROT_MODE_AXISANGLE) /* default XYZ eulers */ - EulOToAxisAngle((float *)value, EULER_ORDER_DEFAULT, pchan->rotAxis, &pchan->rotAngle); - else if(pchan->rotmode == ROT_MODE_QUAT) /* default XYZ eulers */ - EulToQuat((float*)value, pchan->quat); - else - VECCOPY(pchan->eul, value); -} - /* rotation - axis-angle */ static void rna_PoseChannel_rotation_axis_angle_get(PointerRNA *ptr, float *value) { @@ -607,7 +581,6 @@ static void rna_def_pose_channel(BlenderRNA *brna) prop= RNA_def_property(srna, "rotation_euler", PROP_FLOAT, PROP_EULER); RNA_def_property_float_sdna(prop, NULL, "eul"); - RNA_def_property_float_funcs(prop, "rna_PoseChannel_rotation_euler_get", "rna_PoseChannel_rotation_euler_set", NULL); RNA_def_property_ui_text(prop, "Euler Rotation", "Rotation in Eulers."); RNA_def_property_update(prop, NC_OBJECT|ND_TRANSFORM, "rna_Pose_update"); @@ -617,15 +590,14 @@ static void rna_def_pose_channel(BlenderRNA *brna) RNA_def_property_enum_funcs(prop, NULL, "rna_PoseChannel_rotation_mode_set", NULL); RNA_def_property_ui_text(prop, "Rotation Mode", ""); RNA_def_property_update(prop, NC_OBJECT|ND_POSE, "rna_Pose_update"); - - /* These three matrix properties await an implementation of the PROP_MATRIX subtype, which currently doesn't exist. */ + + /* transform matrices - should be read-only since these are set directly by AnimSys evaluation */ prop= RNA_def_property(srna, "channel_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "chan_mat"); RNA_def_property_array(prop, 16); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Channel Matrix", "4x4 matrix, before constraints."); - - /* kaito says this should be not user-editable; I disagree; power users should be able to force this in python; he's the boss. */ + prop= RNA_def_property(srna, "pose_matrix", PROP_FLOAT, PROP_MATRIX); RNA_def_property_float_sdna(prop, NULL, "pose_mat"); RNA_def_property_array(prop, 16); From 6e43a69a8d3dc88594df6f0d15686cad8e7e6646 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 8 Oct 2009 05:53:26 +0000 Subject: [PATCH 024/138] Bugfix #19576: Auto keyframing does not record rotations on object level animation The hardcoded paths for rotation keyframes on objects got broken by my commits to rename the rotation properties. I've taken this opportunity to recode the auto-keyframing code here to use the builtin keyingsets instead of going through and manually calling insert_keyframe(), thus preventing this problem in future. --- source/blender/editors/animation/keyframing.c | 22 ++-- source/blender/editors/animation/keyingsets.c | 27 +--- source/blender/editors/armature/poseSlide.c | 6 +- source/blender/editors/armature/poselib.c | 9 +- source/blender/editors/armature/poseobject.c | 3 +- .../blender/editors/include/ED_keyframing.h | 2 +- .../editors/transform/transform_conversions.c | 118 +++++++----------- 7 files changed, 72 insertions(+), 115 deletions(-) diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 10d45d53761..75218e6ea6e 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -981,12 +981,15 @@ static int insert_key_exec (bContext *C, wmOperator *op) } /* try to insert keyframes for the channels specified by KeyingSet */ - success= modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); - printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success); + success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); + if (G.f & G_DEBUG) + printf("KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success); /* report failure? */ if (success == 0) BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes"); + else + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); /* free temp context-data if available */ if (dsources.first) { @@ -995,10 +998,7 @@ static int insert_key_exec (bContext *C, wmOperator *op) } /* send updates */ - ED_anim_dag_flush_update(C); - - /* for now, only send ND_KEYS for KeyingSets */ - WM_event_add_notifier(C, ND_KEYS, NULL); + ED_anim_dag_flush_update(C); return OPERATOR_FINISHED; } @@ -1132,12 +1132,15 @@ static int delete_key_exec (bContext *C, wmOperator *op) } /* try to insert keyframes for the channels specified by KeyingSet */ - success= modify_keyframes(C, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); - printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success); + success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra); + if (G.f & G_DEBUG) + printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success); /* report failure? */ if (success == 0) BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes"); + else + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); /* free temp context-data if available */ if (dsources.first) { @@ -1148,9 +1151,6 @@ static int delete_key_exec (bContext *C, wmOperator *op) /* send updates */ ED_anim_dag_flush_update(C); - /* for now, only send ND_KEYS for KeyingSets */ - WM_event_add_notifier(C, ND_KEYS, NULL); - return OPERATOR_FINISHED; } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index 99cdf0a86f4..a9a3612b79b 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -1252,9 +1252,8 @@ short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets. * Returns the number of channels that keyframes were added to */ -int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) +int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) { - Scene *scene= CTX_data_scene(C); KS_Path *ksp; int kflag=0, success= 0; char *groupname= NULL; @@ -1319,24 +1318,16 @@ int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet * success+= delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag); } - /* send notifiers and set recalc-flags */ - // TODO: hopefully this doesn't result in execessive flooding of the notifier stack - if (C && ksp->id) { + /* set recalc-flags */ + if (ksp->id) { switch (GS(ksp->id->name)) { case ID_OB: /* Object (or Object-Related) Keyframes */ { Object *ob= (Object *)ksp->id; ob->recalc |= OB_RECALC; - WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, ksp->id); } break; - case ID_MA: /* Material Keyframes */ - WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, ksp->id); - break; - default: /* Any keyframes */ - WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); - break; } } } @@ -1457,24 +1448,16 @@ int modify_keyframes (bContext *C, ListBase *dsources, bAction *act, KeyingSet * MEM_freeN(path); } - /* send notifiers and set recalc-flags */ - // TODO: hopefully this doesn't result in execessive flooding of the notifier stack - if (C && cks->id) { + /* set recalc-flags */ + if (cks->id) { switch (GS(cks->id->name)) { case ID_OB: /* Object (or Object-Related) Keyframes */ { Object *ob= (Object *)cks->id; ob->recalc |= OB_RECALC; - WM_event_add_notifier(C, NC_OBJECT|ND_KEYS, cks->id); } break; - case ID_MA: /* Material Keyframes */ - WM_event_add_notifier(C, NC_MATERIAL|ND_KEYS, cks->id); - break; - default: /* Any keyframes */ - WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); - break; } } } diff --git a/source/blender/editors/armature/poseSlide.c b/source/blender/editors/armature/poseSlide.c index c73208c54c2..1e0df79d0e6 100644 --- a/source/blender/editors/armature/poseSlide.c +++ b/source/blender/editors/armature/poseSlide.c @@ -560,11 +560,11 @@ static void pose_slide_autoKeyframe (bContext *C, tPoseSlideOp *pso) /* insert keyframes */ if (pchan->flag & POSE_LOC) - modify_keyframes(C, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + modify_keyframes(pso->scene, &dsources, NULL, pso->ks_loc, MODIFYKEY_MODE_INSERT, (float)pso->cframe); if (pchan->flag & POSE_ROT) - modify_keyframes(C, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + modify_keyframes(pso->scene, &dsources, NULL, pso->ks_rot, MODIFYKEY_MODE_INSERT, (float)pso->cframe); if (pchan->flag & POSE_SIZE) - modify_keyframes(C, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe); + modify_keyframes(pso->scene, &dsources, NULL, pso->ks_scale, MODIFYKEY_MODE_INSERT, (float)pso->cframe); } } } diff --git a/source/blender/editors/armature/poselib.c b/source/blender/editors/armature/poselib.c index 386cb6512a3..d34da201ef5 100644 --- a/source/blender/editors/armature/poselib.c +++ b/source/blender/editors/armature/poselib.c @@ -329,6 +329,7 @@ static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt) static int poselib_add_exec (bContext *C, wmOperator *op) { + Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); bAction *act = poselib_validate(ob); bArmature *arm= (ob) ? ob->data : NULL; @@ -385,7 +386,7 @@ static int poselib_add_exec (bContext *C, wmOperator *op) /* KeyingSet to use depends on rotation mode (but that's handled by the templates code) */ if (poselib_ks_locrotscale == NULL) poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - modify_keyframes(C, &dsources, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame); + modify_keyframes(scene, &dsources, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame); } } } @@ -772,7 +773,7 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData cks.pchan= pchan; /* now insert the keyframe */ - modify_keyframes(C, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); + modify_keyframes(scene, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); /* clear any unkeyed tags */ if (pchan->bone) @@ -783,10 +784,12 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData if (pchan->bone) pchan->bone->flag |= BONE_UNKEYED; } - } } } + + /* send notifiers for this */ + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); } /* Apply the relevant changes to the pose */ diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c index 461a70bbf86..1531d922e04 100644 --- a/source/blender/editors/armature/poseobject.c +++ b/source/blender/editors/armature/poseobject.c @@ -1089,7 +1089,7 @@ static int pose_paste_exec (bContext *C, wmOperator *op) /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ cks.pchan= pchan; - modify_keyframes(C, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); + modify_keyframes(scene, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA); /* clear any unkeyed tags */ if (chan->bone) @@ -1118,6 +1118,7 @@ static int pose_paste_exec (bContext *C, wmOperator *op) /* notifiers for updates */ WM_event_add_notifier(C, NC_OBJECT|ND_POSE|ND_TRANSFORM, ob); + WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); // XXX not really needed, but here for completeness... return OPERATOR_FINISHED; } diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 92dda4162cc..2b41cb5c9db 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -122,7 +122,7 @@ enum { } eModifyKey_Modes; /* Keyframing Helper Call - use the provided Keying Set to Add/Remove Keyframes */ -int modify_keyframes(struct bContext *C, struct ListBase *dsources, struct bAction *act, struct KeyingSet *ks, short mode, float cfra); +int modify_keyframes(struct Scene *scene, struct ListBase *dsources, struct bAction *act, struct KeyingSet *ks, short mode, float cfra); /* -------- */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 1b11d43c200..d2c1c9f55f0 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -4242,10 +4242,15 @@ void autokeyframe_ob_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode) // TODO: this should probably be done per channel instead... if (autokeyframe_cfra_can_key(scene, id)) { - AnimData *adt= ob->adt; + bCommonKeySrc cks; + ListBase dsources = {&cks, &cks}; float cfra= (float)CFRA; // xxx this will do for now short flag = 0; + /* init common-key-source for use by KeyingSets */ + memset(&cks, 0, sizeof(bCommonKeySrc)); + cks.id= &ob->id; + if (IS_AUTOKEY_FLAG(INSERTNEEDED)) flag |= INSERTKEY_NEEDED; if (IS_AUTOKEY_FLAG(AUTOMATKEY)) @@ -4254,6 +4259,8 @@ void autokeyframe_ob_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode) flag |= INSERTKEY_REPLACE; if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { + AnimData *adt= ob->adt; + /* only key on available channels */ if (adt && adt->action) { for (fcu= adt->action->curves.first; fcu; fcu= fcu->next) { @@ -4292,41 +4299,25 @@ void autokeyframe_ob_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode) doScale = 1; } - // TODO: the group names here are temporary... - // TODO: should this be made to use the builtin KeyingSets instead? + /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */ if (doLoc) { - insert_keyframe(id, NULL, "Object Transform", "location", 0, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "location", 1, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "location", 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doRot) { - insert_keyframe(id, NULL, "Object Transform", "rotation", 0, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "rotation", 1, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "rotation", 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doScale) { - insert_keyframe(id, NULL, "Object Transform", "scale", 0, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "scale", 1, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "scale", 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scale"); + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } } + /* insert keyframe in all (transform) channels */ else { - // TODO: the group names here are temporary... - // TODO: should this be made to use the builtin KeyingSets instead? - insert_keyframe(id, NULL, "Object Transform", "location", 0, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "location", 1, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "location", 2, cfra, flag); - - insert_keyframe(id, NULL, "Object Transform", "rotation", 0, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "rotation", 1, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "rotation", 2, cfra, flag); - - insert_keyframe(id, NULL, "Object Transform", "scale", 0, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "scale", 1, cfra, flag); - insert_keyframe(id, NULL, "Object Transform", "scale", 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } - - // XXX todo... find a way to send notifiers from here... } } @@ -4346,9 +4337,14 @@ void autokeyframe_pose_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode, // TODO: this should probably be done per channel instead... if (autokeyframe_cfra_can_key(scene, id)) { + bCommonKeySrc cks; + ListBase dsources = {&cks, &cks}; float cfra= (float)CFRA; short flag= 0; - char buf[512]; + + /* init common-key-source for use by KeyingSets */ + memset(&cks, 0, sizeof(bCommonKeySrc)); + cks.id= &ob->id; /* flag is initialised from UserPref keyframing settings * - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get @@ -4401,60 +4397,34 @@ void autokeyframe_pose_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode, } if (doLoc) { - sprintf(buf, "pose.pose_channels[\"%s\"].location", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location"); + + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doRot) { - // FIXME: better to just use the keyingsets for this instead... - if (pchan->rotmode == ROT_MODE_QUAT) { - sprintf(buf, "pose.pose_channels[\"%s\"].rotation_quaternion", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 3, cfra, flag); - } - else { - sprintf(buf, "pose.pose_channels[\"%s\"].rotation_euler", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); - } + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation"); + + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } if (doScale) { - sprintf(buf, "pose.pose_channels[\"%s\"].scale", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scale"); + + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } } - /* insert keyframe in any channel that's appropriate */ + /* insert keyframe in all (transform) channels */ else { - sprintf(buf, "pose.pose_channels[\"%s\"].location", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); + KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale"); - // FIXME: better to just use the keyingsets for this instead... - if (pchan->rotmode == ROT_MODE_QUAT) { - sprintf(buf, "pose.pose_channels[\"%s\"].rotation", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 3, cfra, flag); - } - else { - sprintf(buf, "pose.pose_channels[\"%s\"].rotation_euler", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); - } - - sprintf(buf, "pose.pose_channels[\"%s\"].scale", pchan->name); - insert_keyframe(id, NULL, pchan->name, buf, 0, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 1, cfra, flag); - insert_keyframe(id, NULL, pchan->name, buf, 2, cfra, flag); + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra); } } } From da698657cee0500f1f0cff6d4340e016dd34a94e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 8 Oct 2009 06:39:45 +0000 Subject: [PATCH 025/138] Keying Sets - Bugfixes + Auto-Keyframing * Added a new option for Auto-Keyframing which makes it only insert keyframes for the items included in the active Keying Set. This only works for Transform Auto-Keyframing so far (other tools will get it added later). The option is disabled by default. * Fixed bug where adding an 'entire' array to some KeyingSet would only start from the index of the button that the mouse was over at the time * Made some UI tweaks for Keying Sets buttons (still heaps of missing options there). --- release/scripts/ui/buttons_scene.py | 6 +++++ release/scripts/ui/space_userpref.py | 9 ++++--- source/blender/editors/animation/keyingsets.c | 27 ++++++++++++++++++- .../blender/editors/include/ED_keyframing.h | 6 +++++ source/blender/editors/transform/transform.h | 2 +- .../editors/transform/transform_conversions.c | 17 ++++++++++-- source/blender/makesdna/DNA_userdef_types.h | 4 ++- source/blender/makesrna/intern/rna_userdef.c | 10 ++++--- 8 files changed, 70 insertions(+), 11 deletions(-) diff --git a/release/scripts/ui/buttons_scene.py b/release/scripts/ui/buttons_scene.py index 666bbacea50..9bd0019bd6c 100644 --- a/release/scripts/ui/buttons_scene.py +++ b/release/scripts/ui/buttons_scene.py @@ -473,6 +473,9 @@ class SCENE_PT_keying_sets(SceneButtonsPanel): scene = context.scene + row = layout.row() + row.itemL(text="Keying Sets") + row = layout.row() col = row.column() @@ -508,6 +511,9 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel): scene = context.scene ks = scene.active_keying_set + row = layout.row() + row.itemL(text="Paths") + row = layout.row() col = row.column() diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index ce8d03d3292..43c70dac4b1 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -199,13 +199,16 @@ class USERPREF_PT_edit(bpy.types.Panel): sub1 = sub.column() sub1.itemL(text="Keyframing:") sub1.itemR(edit, "use_visual_keying") - sub1.itemR(edit, "auto_keyframe_insert_available", text="Only Insert Available") - sub1.itemR(edit, "auto_keyframe_insert_needed", text="Only Insert Needed") + sub1.itemR(edit, "keyframe_insert_needed", text="Only Insert Needed") sub1.itemS() sub1.itemL(text="New F-Curve Defaults:") sub1.itemR(edit, "new_interpolation_type", text="Interpolation") sub1.itemS() - sub1.itemR(edit, "auto_keying_enable", text="Auto Keyframing") + sub1.itemR(edit, "auto_keying_enable", text="Auto Keyframing:") + sub2 = sub1.column() + sub2.active = edit.auto_keying_enable + sub2.itemR(edit, "auto_keyframe_insert_keyingset", text="Only Insert for Keying Set") + sub2.itemR(edit, "auto_keyframe_insert_available", text="Only Insert Available") sub1.itemS() sub1.itemS() diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index a9a3612b79b..afaa9e3f400 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -337,9 +337,16 @@ static int add_keyingset_button_exec (bContext *C, wmOperator *op) if (path) { /* set flags */ - if (all) + if (all) { pflag |= KSP_FLAG_WHOLE_ARRAY; + /* we need to set the index for this to 0, even though it may break in some cases, this is + * necessary if we want the entire array for most cases to get included without the user + * having to worry about where they clicked + */ + index= 0; + } + /* add path to this setting */ BKE_keyingset_add_destination(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME); success= 1; @@ -1109,6 +1116,24 @@ KeyingSet *ANIM_builtin_keyingset_get_named (KeyingSet *prevKS, char name[]) return NULL; } + +/* Get the active Keying Set for the Scene provided */ +KeyingSet *ANIM_scene_get_active_keyingset (Scene *scene) +{ + if (ELEM(NULL, scene, scene->keyingsets.first)) + return NULL; + + /* currently, there are several possibilities here: + * - 0: no active keying set + * - > 0: one of the user-defined Keying Sets, but indices start from 0 (hence the -1) + * - < 0: a builtin keying set (XXX this isn't enabled yet so that we don't get errors on reading back files) + */ + if (scene->active_keyingset > 0) + return BLI_findlink(&scene->keyingsets, scene->active_keyingset-1); + else // for now... + return NULL; +} + /* ******************************************* */ /* KEYFRAME MODIFICATION */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 2b41cb5c9db..802ceff1c07 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -135,6 +135,12 @@ struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, cha /* Initialise builtin KeyingSets on startup */ void init_builtin_keyingsets(void); + +/* -------- */ + +/* Get the active KeyingSet for the given scene */ +struct KeyingSet *ANIM_scene_get_active_keyingset(struct Scene *scene); + /* ************ Drivers ********************** */ /* Returns whether there is a driver in the copy/paste buffer to paste */ diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index ee6871d67bd..1c170a31c45 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -216,7 +216,7 @@ typedef struct TransData { void *extra; /* extra data (mirrored element pointer, in editmode mesh to EditVert) (editbone for roll fixing) (...) */ short flag; /* Various flags */ short protectflag; /* If set, copy of Object or PoseChannel protection */ - int rotOrder; /* rotation order (for eulers), as defined in BLI_arithb.h */ + int rotOrder; /* rotation mode, as defined in eRotationModes (DNA_action_types.h) */ } TransData; typedef struct MouseInput { diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index d2c1c9f55f0..a9c3e4676a0 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -4242,6 +4242,7 @@ void autokeyframe_ob_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode) // TODO: this should probably be done per channel instead... if (autokeyframe_cfra_can_key(scene, id)) { + KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); bCommonKeySrc cks; ListBase dsources = {&cks, &cks}; float cfra= (float)CFRA; // xxx this will do for now @@ -4258,7 +4259,12 @@ void autokeyframe_ob_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode) if (IS_AUTOKEY_MODE(scene, EDITKEYS)) flag |= INSERTKEY_REPLACE; - if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { + + if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) { + /* only insert into active keyingset */ + modify_keyframes(scene, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); + } + else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { AnimData *adt= ob->adt; /* only key on available channels */ @@ -4337,6 +4343,7 @@ void autokeyframe_pose_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode, // TODO: this should probably be done per channel instead... if (autokeyframe_cfra_can_key(scene, id)) { + KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene); bCommonKeySrc cks; ListBase dsources = {&cks, &cks}; float cfra= (float)CFRA; @@ -4363,8 +4370,14 @@ void autokeyframe_pose_cb_func(Scene *scene, View3D *v3d, Object *ob, int tmode, /* clear any 'unkeyed' flag it may have */ pchan->bone->flag &= ~BONE_UNKEYED; + /* only insert into active keyingset? */ + if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) { + /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */ + cks.pchan= pchan; + modify_keyframes(scene, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra); + } /* only insert into available channels? */ - if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { + else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) { if (act) { for (fcu= act->curves.first; fcu; fcu= fcu->next) insert_keyframe(id, act, ((fcu->grp)?(fcu->grp->name):(NULL)), fcu->rna_path, fcu->array_index, cfra, flag); diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index edfc4999d80..5aa1aa6dfff 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -412,10 +412,12 @@ extern UserDef U; /* from blenkernel blender.c */ #define AUTOKEY_MODE_EDITKEYS 5 /* Auto-Keying flag */ - /* U.autokey_flag */ + /* U.autokey_flag (not strictly used when autokeying only - is also used when keyframing these days) */ #define AUTOKEY_FLAG_INSERTAVAIL (1<<0) #define AUTOKEY_FLAG_INSERTNEEDED (1<<1) #define AUTOKEY_FLAG_AUTOMATKEY (1<<2) + /* U.autokey_flag (strictly autokeying only) */ +#define AUTOKEY_FLAG_ONLYKEYINGSET (1<<6) /* toolsettings->autokey_flag */ #define ANIMRECORD_FLAG_WITHNLA (1<<10) diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 1c6bd6515ff..8f999300c71 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1881,10 +1881,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) prop= RNA_def_property(srna, "auto_keyframe_insert_available", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_INSERTAVAIL); RNA_def_property_ui_text(prop, "Auto Keyframe Insert Available", "Automatic keyframe insertion in available curves."); - - prop= RNA_def_property(srna, "auto_keyframe_insert_needed", PROP_BOOLEAN, PROP_NONE); + + prop= RNA_def_property(srna, "auto_keyframe_insert_keyingset", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_ONLYKEYINGSET); + RNA_def_property_ui_text(prop, "Auto Keyframe Insert Keying Set", "Automatic keyframe insertion using active Keying Set."); + + prop= RNA_def_property(srna, "keyframe_insert_needed", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_INSERTNEEDED); - RNA_def_property_ui_text(prop, "Auto Keyframe Insert Needed", "Automatic keyframe insertion only when keyframe needed."); + RNA_def_property_ui_text(prop, "Keyframe Insert Needed", "Keyframe insertion only when keyframe needed."); prop= RNA_def_property(srna, "use_visual_keying", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_AUTOMATKEY); From df6c18e9638e9be36361910e86079cd6544f769a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 07:54:20 +0000 Subject: [PATCH 026/138] - object.selected is now editable (uses update function to flag the scene base) - editing properties from python wasnt running their update function. - missing commas made dir(context) give joined strings. - added __undo__ as an operator class attribute so python ops can be set as undoable. (like existing __register__) --- release/scripts/ui/space_view3d.py | 43 ++++++++++++++++++- .../blender/editors/screen/screen_context.c | 2 +- .../editors/space_view3d/space_view3d.c | 6 +-- source/blender/makesrna/intern/rna_object.c | 11 ++++- .../blender/python/intern/bpy_operator_wrap.c | 18 ++++++-- source/blender/python/intern/bpy_rna.c | 5 ++- 6 files changed, 73 insertions(+), 12 deletions(-) diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index 5827739aa53..976c04a63bb 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -179,6 +179,7 @@ class VIEW3D_MT_select_object(bpy.types.Menu): layout.itemO("object.select_by_layer", text="Select All by Layer") layout.item_enumO("object.select_by_type", "type", "", text="Select All by Type...") layout.itemO("object.select_grouped", text="Select Grouped...") + layout.itemO("object.select_pattern", text="Select Pattern...") class VIEW3D_MT_select_pose(bpy.types.Menu): __space_type__ = 'VIEW_3D' @@ -1306,7 +1307,42 @@ class VIEW3D_PT_transform_orientations(bpy.types.Panel): col.itemO("TFM_OT_select_orientation", text="Select") col.itemO("TFM_OT_create_orientation", text="Create") col.itemO("TFM_OT_delete_orientation", text="Delete") - + +# Operators + +class OBJECT_OT_select_pattern(bpy.types.Operator): + '''Select object matching a naming pattern.''' + __idname__ = "object.select_pattern" + __label__ = "Select Pattern" + __register__ = True + __undo__ = True + __props__ = [ + bpy.props.StringProperty(attr="pattern", name="Pattern", description="Name filter using '*' and '?' wildcard chars", maxlen= 32, default= "*"), + bpy.props.BoolProperty(attr="case_sensitive", name="Case Sensitive", description="Do a case sensitive compare", default= False), + ] + + def execute(self, context): + + import fnmatch + if self.case_sensitive: pattern_match = fnmatch.fnmatchcase + else: pattern_match = lambda a, b: fnmatch.fnmatchcase(a.upper(), b.upper()) + + for ob in context.visible_objects: + if pattern_match(ob.name, self.pattern): + ob.selected = True + + return ('FINISHED',) + + # TODO - python cant do popups yet + ''' + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + ''' + + + bpy.types.register(VIEW3D_HT_header) # Header bpy.types.register(VIEW3D_MT_view) #View Menus @@ -1382,4 +1418,7 @@ bpy.types.register(VIEW3D_PT_3dview_display) bpy.types.register(VIEW3D_PT_3dview_meshdisplay) bpy.types.register(VIEW3D_PT_3dview_curvedisplay) bpy.types.register(VIEW3D_PT_background_image) -bpy.types.register(VIEW3D_PT_transform_orientations) \ No newline at end of file +bpy.types.register(VIEW3D_PT_transform_orientations) + +bpy.ops.add(OBJECT_OT_select_pattern) + diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 17c51a7b7d3..e573ef06247 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -52,7 +52,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult if(CTX_data_dir(member)) { static const char *dir[] = { "scene", "selected_objects", "selected_bases", - "selected_editable_objects", "selected_editable_bases" + "selected_editable_objects", "selected_editable_bases", "active_base", "active_object", "edit_object", "sculpt_object", "vertex_paint_object", "weight_paint_object", "texture_paint_object", "brush", "particle_edit_object", NULL}; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index c175f835d67..735f3df9b09 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -620,10 +620,10 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes if(CTX_data_dir(member)) { static const char *dir[] = { - "selected_objects", "selected_bases" "selected_editable_objects", - "selected_editable_bases" "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", + "selected_objects", "selected_bases", "selected_editable_objects", + "selected_editable_bases", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", "active_base", "active_object", "visible_bones", "editable_bones", - "selected_bones", "selected_editable_bones" "visible_pchans", + "selected_bones", "selected_editable_bones", "visible_pchans", "selected_pchans", "active_bone", "active_pchan", NULL}; CTX_data_dir_set(result, dir); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 013d455b1b3..694eb7e23e4 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -126,6 +126,14 @@ static void rna_Object_dependency_update(bContext *C, PointerRNA *ptr) DAG_scene_sort(CTX_data_scene(C)); } +/* when changing the selection flag the scene needs updating */ +static void rna_Object_select_update(bContext *C, PointerRNA *ptr) +{ + Object *ob= (Object*)ptr->id.data; + short mode = ob->flag & SELECT ? BA_SELECT : BA_DESELECT; + ED_base_object_select(object_in_scene(ob, CTX_data_scene(C)), mode); +} + static void rna_Object_layer_update(bContext *C, PointerRNA *ptr) { Object *ob= (Object*)ptr->id.data; @@ -1145,9 +1153,8 @@ static void rna_def_object(BlenderRNA *brna) prop= RNA_def_property(srna, "selected", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SELECT); - RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Selected", "Object selection state."); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_select_update"); /* parent and track */ diff --git a/source/blender/python/intern/bpy_operator_wrap.c b/source/blender/python/intern/bpy_operator_wrap.c index bbf657d8ce0..bb0cea9e761 100644 --- a/source/blender/python/intern/bpy_operator_wrap.c +++ b/source/blender/python/intern/bpy_operator_wrap.c @@ -47,6 +47,7 @@ #define PYOP_ATTR_IDNAME_BL "__idname_bl__" /* our own name converted into blender syntax, users wont see this */ #define PYOP_ATTR_DESCRIPTION "__doc__" /* use pythons docstring */ #define PYOP_ATTR_REGISTER "__register__" /* True/False. if this python operator should be registered */ +#define PYOP_ATTR_UNDO "__undo__" /* True/False. if this python operator should be undone */ static struct BPY_flag_def pyop_ret_flags[] = { {"RUNNING_MODAL", OPERATOR_RUNNING_MODAL}, @@ -277,16 +278,27 @@ void PYTHON_OT_wrapper(wmOperatorType *ot, void *userdata) ot->pyop_data= userdata; /* flags */ + ot->flag= 0; + item= PyObject_GetAttrString(py_class, PYOP_ATTR_REGISTER); if (item) { - ot->flag= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0; + ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_REGISTER:0; Py_DECREF(item); } else { - ot->flag= OPTYPE_REGISTER; /* unspesified, leave on for now to help debug */ PyErr_Clear(); } - + item= PyObject_GetAttrString(py_class, PYOP_ATTR_UNDO); + if (item) { + ot->flag |= PyObject_IsTrue(item)!=0 ? OPTYPE_UNDO:0; + Py_DECREF(item); + } + else { + PyErr_Clear(); + } + + + props= PyObject_GetAttrString(py_class, PYOP_ATTR_PROP); if (props) { diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 1f800be266b..42b905dc0d8 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -762,7 +762,10 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v break; } } - + + /* Run rna property functions */ + RNA_property_update(BPy_GetContext(), ptr, prop); + return 0; } From 5a7db36b1d6a17d714ad0056d02095feab371e80 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 08:01:51 +0000 Subject: [PATCH 027/138] missed this in last commit comments, Pattern Select operator, access from the object select menu Glob strings like "Lear*.brown" and "Tree.0?", option for case sensitive and extend the existing selection. currently the default string is "*" which needs to be edited in the redo-panel in the toolbox since there is no way to get a text input for python. This replaces 2.4x's data browser Shift+F4, pattern select. --- release/scripts/ui/space_view3d.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index 976c04a63bb..ef1947dbb39 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -1319,6 +1319,7 @@ class OBJECT_OT_select_pattern(bpy.types.Operator): __props__ = [ bpy.props.StringProperty(attr="pattern", name="Pattern", description="Name filter using '*' and '?' wildcard chars", maxlen= 32, default= "*"), bpy.props.BoolProperty(attr="case_sensitive", name="Case Sensitive", description="Do a case sensitive compare", default= False), + bpy.props.BoolProperty(attr="extend", name="Extend", description="Extend the existing selection", default= True), ] def execute(self, context): @@ -1330,6 +1331,8 @@ class OBJECT_OT_select_pattern(bpy.types.Operator): for ob in context.visible_objects: if pattern_match(ob.name, self.pattern): ob.selected = True + elif not self.extend: + ob.selected = False return ('FINISHED',) From 8f154364f28d53c58b9a0022f8c36ab787477492 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 09:22:39 +0000 Subject: [PATCH 028/138] separate material lost all materials for the new mesh --- source/blender/blenkernel/BKE_material.h | 4 ++-- source/blender/blenkernel/intern/material.c | 18 +++++++++++------- source/blender/blenkernel/intern/object.c | 1 + source/blender/editors/mesh/editmesh.c | 1 + 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index b6645ef8737..85316dddedf 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -62,8 +62,8 @@ void assign_matarar(struct Object *ob, struct Material ***matar, int totcol); int find_material_index(struct Object *ob, struct Material *ma); -void object_add_material_slot(struct Object *ob); -void object_remove_material_slot(struct Object *ob); +int object_add_material_slot(struct Object *ob); +int object_remove_material_slot(struct Object *ob); /* rendering */ diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index b44c59baaca..c1093c119dc 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -630,8 +630,7 @@ void assign_matarar(struct Object *ob, struct Material ***matar, int totcol) { int i, actcol_orig= ob->actcol; - while(ob->totcol) - object_remove_material_slot(ob); + while(object_remove_material_slot(ob)) {}; /* now we have the right number of slots */ for(i=0; itotcol>=MAXMAT) return; + if(ob==0) return FALSE; + if(ob->totcol>=MAXMAT) return FALSE; ma= give_current_material(ob, ob->actcol); assign_material(ob, ma, ob->totcol+1); ob->actcol= ob->totcol; + return TRUE; } static void do_init_render_material(Material *ma, int r_mode, float *amb) @@ -889,7 +889,7 @@ void automatname(Material *ma) } -void object_remove_material_slot(Object *ob) +int object_remove_material_slot(Object *ob) { Material *mao, ***matarar; Object *obt; @@ -898,7 +898,7 @@ void object_remove_material_slot(Object *ob) short *totcolp; int a, actcol; - if(ob==NULL || ob->totcol==0) return; + if(ob==NULL || ob->totcol==0) return FALSE; /* take a mesh/curve/mball as starting point, remove 1 index, * AND with all objects that share the ob->data @@ -909,6 +909,8 @@ void object_remove_material_slot(Object *ob) totcolp= give_totcolp(ob); matarar= give_matarar(ob); + if(*matarar==NULL) return FALSE; + /* we delete the actcol */ if(ob->totcol) { mao= (*matarar)[ob->actcol-1]; @@ -971,6 +973,8 @@ void object_remove_material_slot(Object *ob) } freedisplist(&ob->disp); } + + return TRUE; } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 89757533fb8..0b0a7a54c38 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1233,6 +1233,7 @@ Object *copy_object(Object *ob) if(ob->totcol) { obn->mat= MEM_dupallocN(ob->mat); obn->matbits= MEM_dupallocN(ob->matbits); + obn->totcol= ob->totcol; } if(ob->bb) obn->bb= MEM_dupallocN(ob->bb); diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index d540151337d..1e3105f5c97 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -1343,6 +1343,7 @@ static int mesh_separate_selected(Scene *scene, Base *editbase) /* 2 */ basenew->object->data= menew= add_mesh(me->id.name); /* empty */ + assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ me->id.us--; make_editMesh(scene, basenew->object); emnew= menew->edit_mesh; From 14f62c132136ba8696cf204fb421ba4f10414a6a Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Thu, 8 Oct 2009 10:18:14 +0000 Subject: [PATCH 029/138] Smoke: * Enable external forces like e.g. wind --- intern/smoke/extern/smoke_API.h | 4 ++ intern/smoke/intern/FLUID_3D.cpp | 14 ++--- intern/smoke/intern/smoke_API.cpp | 15 +++++ release/scripts/ui/buttons_physics_smoke.py | 15 ++++- source/blender/blenkernel/intern/smoke.c | 58 ++++++++++++++++---- source/blender/blenloader/intern/readfile.c | 7 +++ source/blender/blenloader/intern/writefile.c | 3 + source/blender/makesdna/DNA_smoke_types.h | 3 +- source/blender/makesrna/intern/rna_smoke.c | 5 ++ 9 files changed, 105 insertions(+), 19 deletions(-) diff --git a/intern/smoke/extern/smoke_API.h b/intern/smoke/extern/smoke_API.h index 5607df70cf3..ea106c81303 100644 --- a/intern/smoke/extern/smoke_API.h +++ b/intern/smoke/extern/smoke_API.h @@ -50,6 +50,10 @@ float *smoke_get_velocity_x(struct FLUID_3D *fluid); float *smoke_get_velocity_y(struct FLUID_3D *fluid); float *smoke_get_velocity_z(struct FLUID_3D *fluid); +float *smoke_get_force_x(struct FLUID_3D *fluid); +float *smoke_get_force_y(struct FLUID_3D *fluid); +float *smoke_get_force_z(struct FLUID_3D *fluid); + unsigned char *smoke_get_obstacle(struct FLUID_3D *fluid); size_t smoke_get_index(int x, int max_x, int y, int max_y, int z); diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp index bb2227801c7..729d73bb4f3 100644 --- a/intern/smoke/intern/FLUID_3D.cpp +++ b/intern/smoke/intern/FLUID_3D.cpp @@ -184,13 +184,6 @@ void FLUID_3D::step() { // addSmokeTestCase(_density, _res); // addSmokeTestCase(_heat, _res); - - // wipe forces - for (int i = 0; i < _totalCells; i++) - { - _xForce[i] = _yForce[i] = _zForce[i] = 0.0f; - // _obstacles[i] &= ~2; - } wipeBoundaries(); @@ -232,6 +225,13 @@ void FLUID_3D::step() // todo xxx dg: only clear obstacles, not boundaries // memset(_obstacles, 0, sizeof(unsigned char)*_xRes*_yRes*_zRes); + + // wipe forces + // for external forces we can't do it at the beginning of this function but at the end + for (int i = 0; i < _totalCells; i++) + { + _xForce[i] = _yForce[i] = _zForce[i] = 0.0f; + } } ////////////////////////////////////////////////////////////////////// diff --git a/intern/smoke/intern/smoke_API.cpp b/intern/smoke/intern/smoke_API.cpp index 67df6e805d8..2d1d590fcc0 100644 --- a/intern/smoke/intern/smoke_API.cpp +++ b/intern/smoke/intern/smoke_API.cpp @@ -235,6 +235,21 @@ extern "C" float *smoke_get_velocity_z(FLUID_3D *fluid) return fluid->_zVelocity; } +extern "C" float *smoke_get_force_x(FLUID_3D *fluid) +{ + return fluid->_xForce; +} + +extern "C" float *smoke_get_force_y(FLUID_3D *fluid) +{ + return fluid->_yForce; +} + +extern "C" float *smoke_get_force_z(FLUID_3D *fluid) +{ + return fluid->_zForce; +} + extern "C" float *smoke_turbulence_get_density(WTURBULENCE *wt) { return wt ? wt->getDensityBig() : NULL; diff --git a/release/scripts/ui/buttons_physics_smoke.py b/release/scripts/ui/buttons_physics_smoke.py index 1541b0bae14..53a7ec9c10c 100644 --- a/release/scripts/ui/buttons_physics_smoke.py +++ b/release/scripts/ui/buttons_physics_smoke.py @@ -1,7 +1,8 @@ import bpy -from buttons_particle import point_cache_ui +from buttons_physics_common import point_cache_ui +from buttons_physics_common import effector_weights_ui class PhysicButtonsPanel(bpy.types.Panel): __space_type__ = 'PROPERTIES' @@ -171,8 +172,20 @@ class PHYSICS_PT_smoke_cache_highres(PhysicButtonsPanel): cache = md.point_cache_high point_cache_ui(self, cache, cache.baked==False, 0, 1) + +class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel): + __label__ = "Smoke Field Weights" + __default_closed__ = True + + def poll(self, context): + return (context.smoke) + + def draw(self, context): + domain = context.smoke.domain_settings + effector_weights_ui(self, domain.effector_weights) bpy.types.register(PHYSICS_PT_smoke) +bpy.types.register(PHYSICS_PT_smoke_field_weights) bpy.types.register(PHYSICS_PT_smoke_cache) bpy.types.register(PHYSICS_PT_smoke_highres) bpy.types.register(PHYSICS_PT_smoke_groups) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index f1fae4fa678..c1e79651c59 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -53,6 +53,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_customdata.h" #include "BKE_DerivedMesh.h" +#include "BKE_effect.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -547,6 +548,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd) if(smd->domain->wt) smoke_turbulence_free(smd->domain->wt); + if(smd->domain->effector_weights) + MEM_freeN(smd->domain->effector_weights); + smd->domain->effector_weights = NULL; + BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); smd->domain->point_cache[0] = NULL; BKE_ptcache_free_list(&(smd->domain->ptcaches[1])); @@ -714,6 +719,7 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->diss_speed = 5; // init 3dview buffer smd->domain->viewsettings = 0; + smd->domain->effector_weights = BKE_add_effector_weights(NULL); } else if(smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -938,21 +944,53 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) } // do effectors - /* - if(sds->eff_group) { - for(go = sds->eff_group->gobject.first; go; go = go->next) + ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); + + if(effectors) { - if(go->ob) - { - if(ob->pd) - { - - } + float *density = smoke_get_density(sds->fluid); + float *force_x = smoke_get_force_x(sds->fluid); + float *force_y = smoke_get_force_y(sds->fluid); + float *force_z = smoke_get_force_z(sds->fluid); + float *velocity_x = smoke_get_velocity_x(sds->fluid); + float *velocity_y = smoke_get_velocity_y(sds->fluid); + float *velocity_z = smoke_get_velocity_z(sds->fluid); + int x, y, z; + + // precalculate wind forces + for(x = 0; x < sds->res[0]; x++) + for(y = 0; y < sds->res[1]; y++) + for(z = 0; z < sds->res[2]; z++) + { + EffectedPoint epoint; + float voxelCenter[3], vel[3], retvel[3]; + + unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); + + if(density[index] < FLT_EPSILON) + continue; + + vel[0] = velocity_x[index]; + vel[1] = velocity_y[index]; + vel[2] = velocity_z[index]; + + voxelCenter[0] = sds->p0[0] + sds->dx * x + sds->dx * 0.5; + voxelCenter[1] = sds->p0[1] + sds->dx * y + sds->dx * 0.5; + voxelCenter[2] = sds->p0[2] + sds->dx * z + sds->dx * 0.5; + + pd_point_from_loc(scene, voxelCenter, vel, index, &epoint); + pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); + + // TODO dg - do in force! + force_x[index] += MIN2(MAX2(-1.0, retvel[0] * 0.002), 1.0); + force_y[index] += MIN2(MAX2(-1.0, retvel[1] * 0.002), 1.0); + force_z[index] += MIN2(MAX2(-1.0, retvel[2] * 0.002), 1.0); } } + + pdEndEffectors(&effectors); } - */ // do collisions if(1) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 989e2b3fa9e..a832cae161b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3655,6 +3655,8 @@ static void lib_link_object(FileData *fd, Main *main) smd->domain->coll_group = newlibadr_us(fd, ob->id.lib, smd->domain->coll_group); smd->domain->eff_group = newlibadr_us(fd, ob->id.lib, smd->domain->eff_group); smd->domain->fluid_group = newlibadr_us(fd, ob->id.lib, smd->domain->fluid_group); + + smd->domain->effector_weights->group = newlibadr(fd, ob->id.lib, smd->domain->effector_weights->group); } } @@ -3784,6 +3786,11 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) smd->domain->tex_shadow = NULL; smd->domain->tex_wt = NULL; + if(smd->domain->effector_weights) + smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights); + else + smd->domain->effector_weights = BKE_add_effector_weights(NULL); + direct_link_pointcache_list(fd, &(smd->domain->ptcaches[0]), &(smd->domain->point_cache[0])); direct_link_pointcache_list(fd, &(smd->domain->ptcaches[1]), &(smd->domain->point_cache[1])); } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index c92c0909d3b..25cbd4b65e7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1153,7 +1153,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) SmokeModifierData *smd = (SmokeModifierData*) md; if(smd->type & MOD_SMOKE_TYPE_DOMAIN) + { writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain); + writestruct(wd, DATA, "EffectorWeights", 1, smd->domain->effector_weights); + } else if(smd->type & MOD_SMOKE_TYPE_FLOW) writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow); else if(smd->type & MOD_SMOKE_TYPE_COLL) diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index 4e4714cdaa1..6cf308aa0ad 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -45,7 +45,7 @@ typedef struct SmokeDomainSettings { struct SmokeModifierData *smd; /* for fast RNA access */ struct FLUID_3D *fluid; struct Group *fluid_group; - struct Group *eff_group; // effector group for e.g. wind force + struct Group *eff_group; // UNUSED struct Group *coll_group; // collision objects group struct WTURBULENCE *wt; // WTURBULENCE object, if active struct GPUTexture *tex; @@ -75,6 +75,7 @@ typedef struct SmokeDomainSettings { int v3dnum; struct PointCache *point_cache[2]; /* definition is in DNA_object_force.h */ struct ListBase ptcaches[2]; + struct EffectorWeights *effector_weights; } SmokeDomainSettings; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index 7bccd685c1d..c8193bb4005 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -220,6 +220,11 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "point_cache[1]"); RNA_def_property_ui_text(prop, "Point Cache", ""); + + prop= RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "EffectorWeights"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Effector Weights", ""); } static void rna_def_smoke_flow_settings(BlenderRNA *brna) From c1302cfa95b725601bfb35760cc670b92bc2ae57 Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Thu, 8 Oct 2009 11:12:03 +0000 Subject: [PATCH 030/138] 2.5 MSVC9 projectfiles Quick update: * added new raytrace lib * added gpu_buffer.c --- projectfiles_vc9/blender/blender.sln | 26 ++++++++++++++++++- projectfiles_vc9/blender/gpu/BL_gpu.vcproj | 4 +++ .../blender/render/BRE_render.vcproj | 16 ++++++++++-- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/projectfiles_vc9/blender/blender.sln b/projectfiles_vc9/blender/blender.sln index d7c16229049..936e444ed12 100644 --- a/projectfiles_vc9/blender/blender.sln +++ b/projectfiles_vc9/blender/blender.sln @@ -13,6 +13,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "blender", "blender.vcproj", {884D8731-654C-4C7F-9A75-8F37A305BE1E} = {884D8731-654C-4C7F-9A75-8F37A305BE1E} {79D0B232-208C-F208-DA71-79B4AC088602} = {79D0B232-208C-F208-DA71-79B4AC088602} {E645CC32-4823-463E-82F0-46ADDE664018} = {E645CC32-4823-463E-82F0-46ADDE664018} + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1} = {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1} {7495FE37-933A-4AC1-BB2A-B3FDB4DE4284} = {7495FE37-933A-4AC1-BB2A-B3FDB4DE4284} {51FB3D48-2467-4BFA-A321-D848252B437E} = {51FB3D48-2467-4BFA-A321-D848252B437E} {FFD3C64A-30E2-4BC7-BC8F-51818C320400} = {FFD3C64A-30E2-4BC7-BC8F-51818C320400} @@ -61,6 +62,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BKE_blenkernel", "blenkernel\BKE_blenkernel.vcproj", "{CAE37E91-6570-43AC-A4B4-7A37A4B0FC94}" ProjectSection(ProjectDependencies) = postProject {02110D03-59DB-4571-8787-72B3C03B2F2D} = {02110D03-59DB-4571-8787-72B3C03B2F2D} + {138DD16C-CC78-4F6C-A898-C8DA68D89067} = {138DD16C-CC78-4F6C-A898-C8DA68D89067} {9C71A793-C177-4CAB-8EC5-923D500B39F8} = {9C71A793-C177-4CAB-8EC5-923D500B39F8} EndProjectSection EndProject @@ -231,9 +233,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EXT_build_install_all", ".. {79D0B232-208C-F208-DA71-79B4AC088602} = {79D0B232-208C-F208-DA71-79B4AC088602} {FFD3C64A-30E2-4BC7-BC8F-51818C320400} = {FFD3C64A-30E2-4BC7-BC8F-51818C320400} {EADC3C5A-6C51-4F03-8038-1553E7D7F740} = {EADC3C5A-6C51-4F03-8038-1553E7D7F740} - {BAC615B0-F1AF-418B-8D23-A10FD8870D6A} = {BAC615B0-F1AF-418B-8D23-A10FD8870D6A} {8BFA4082-773B-D100-BC24-659083BA023F} = {8BFA4082-773B-D100-BC24-659083BA023F} {BAC615B0-F1AF-418B-8D23-A10FD8870D6A} = {BAC615B0-F1AF-418B-8D23-A10FD8870D6A} + {BAC615B0-F1AF-418B-8D23-A10FD8870D6A} = {BAC615B0-F1AF-418B-8D23-A10FD8870D6A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "INT_boolop", "..\..\intern\boolop\make\msvc_9_0\boolop.vcproj", "{EB75F4D6-2970-4A3A-8D99-2BAD7201C0E9}" @@ -328,6 +330,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EXT_lzma", "..\..\extern\lz EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EXT_lzo", "..\..\extern\lzo\make\msvc_9_0\lzo.vcproj", "{8BFA4082-773B-D100-BC24-659083BA023F}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BRE_raytrace", "render\BRE_raytrace.vcproj", "{37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution 3D Plugin Debug|Win32 = 3D Plugin Debug|Win32 @@ -1545,6 +1549,26 @@ Global {8BFA4082-773B-D100-BC24-659083BA023F}.Debug|Win32.Build.0 = 3D Plugin Debug|Win32 {8BFA4082-773B-D100-BC24-659083BA023F}.Release|Win32.ActiveCfg = 3D Plugin Release|Win32 {8BFA4082-773B-D100-BC24-659083BA023F}.Release|Win32.Build.0 = 3D Plugin Release|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3D Plugin Debug|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3D Plugin Debug|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3D Plugin Release|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3D Plugin Release|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3DPlugin Debug|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3DPlugin Debug|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3DPlugin Release|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.3DPlugin Release|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Blender Debug|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Blender Debug|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Blender Release|Win32.ActiveCfg = Blender Release|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Blender Release|Win32.Build.0 = Blender Release|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.BlenderPlayer Debug|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.BlenderPlayer Debug|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.BlenderPlayer Release|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.BlenderPlayer Release|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Debug|Win32.ActiveCfg = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Debug|Win32.Build.0 = Blender Debug|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Release|Win32.ActiveCfg = Blender Release|Win32 + {37DB6A34-2E91-4ADB-BC1A-02F6D0A5E2F1}.Release|Win32.Build.0 = Blender Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/projectfiles_vc9/blender/gpu/BL_gpu.vcproj b/projectfiles_vc9/blender/gpu/BL_gpu.vcproj index db96ab440b9..0b2927e9ee2 100644 --- a/projectfiles_vc9/blender/gpu/BL_gpu.vcproj +++ b/projectfiles_vc9/blender/gpu/BL_gpu.vcproj @@ -474,6 +474,10 @@ Name="Source Files" Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" > + + diff --git a/projectfiles_vc9/blender/render/BRE_render.vcproj b/projectfiles_vc9/blender/render/BRE_render.vcproj index 4b223ddcdc3..358549f19c1 100644 --- a/projectfiles_vc9/blender/render/BRE_render.vcproj +++ b/projectfiles_vc9/blender/render/BRE_render.vcproj @@ -215,11 +215,23 @@ > + + + + + + Date: Thu, 8 Oct 2009 11:24:06 +0000 Subject: [PATCH 031/138] Fixed #19571 (was crashing when building a raytree from a scene withouth any geometry) --- .../render/extern/include/RE_raytrace.h | 1 + .../render/intern/raytrace/rayobject.cpp | 40 +++++++++++++++++++ .../blender/render/intern/source/rayshade.c | 6 +++ 3 files changed, 47 insertions(+) diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h index 22d55bb1a91..7d430d5550a 100644 --- a/source/blender/render/extern/include/RE_raytrace.h +++ b/source/blender/render/extern/include/RE_raytrace.h @@ -83,6 +83,7 @@ void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max); /* RayObject constructors */ RayObject* RE_rayobject_octree_create(int ocres, int size); RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob); +RayObject* RE_rayobject_empty_create(); RayObject* RE_rayobject_blibvh_create(int size); /* BLI_kdopbvh.c */ RayObject* RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */ diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index 95387cf1ee4..621fd3f794e 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -535,3 +535,43 @@ int RE_rayobjectcontrol_test_break(RayObjectControl *control) return 0; } + + +/* + * Empty raytree + */ +static int RE_rayobject_empty_intersect(RayObject *o, Isect *is) +{ + return 0; +} + +static void RE_rayobject_empty_free(RayObject *o) +{ +} + +static void RE_rayobject_empty_bb(RayObject *o, float *min, float *max) +{ + return; +} + +static float RE_rayobject_empty_cost(RayObject *o) +{ + return 0.0; +} + +static RayObjectAPI empty_api = +{ + RE_rayobject_empty_intersect, + NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob); + NULL, //static void RE_rayobject_instance_done(RayObject *o); + RE_rayobject_empty_free, + RE_rayobject_empty_bb, + RE_rayobject_empty_cost +}; + +static RayObject empty_raytree = { &empty_api, {0, 0} }; + +RayObject *RE_rayobject_empty_create() +{ + return RE_rayobject_unalignRayAPI( &empty_raytree ); +} diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 881a549ad96..4ad4d6370f8 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -335,6 +335,12 @@ static void makeraytree_single(Render *re) } } + if(faces + special == 0) + { + re->raytree = RE_rayobject_empty_create(); + return; + } + //Create raytree raytree = re->raytree = RE_rayobject_create( re, re->r.raytrace_structure, faces+special ); From 5ce33cf2bd2def709c9124cc6a7e538e388f1d62 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 8 Oct 2009 11:29:27 +0000 Subject: [PATCH 032/138] A few fixes: * Loading old files didn't initialise the new rotation variables properly * Fixed some errors with the newly added operator for copying RNA-paths for properties * Auto-keyframing now correctly refreshes animation editors after adding keyframes. Made the keyingsets code send notifiers again, but now using the newly added WM_main_event_add() (thanks Brecht) * A few UI tweaks again for animation stuff (timeline, keyingsets UI) --- release/scripts/ui/buttons_object.py | 2 -- release/scripts/ui/buttons_scene.py | 4 ++-- release/scripts/ui/space_time.py | 2 +- source/blender/blenloader/intern/readfile.c | 18 ++++++++++++++++++ source/blender/editors/animation/drivers.c | 13 ++++++------- source/blender/editors/animation/keyingsets.c | 7 +++++++ .../blender/editors/interface/interface_anim.c | 7 ++++--- .../blender/editors/space_outliner/outliner.c | 2 ++ .../makesrna/intern/rna_animation_api.c | 1 + 9 files changed, 41 insertions(+), 15 deletions(-) diff --git a/release/scripts/ui/buttons_object.py b/release/scripts/ui/buttons_object.py index d546ddb8fd8..98ac462f2d4 100644 --- a/release/scripts/ui/buttons_object.py +++ b/release/scripts/ui/buttons_object.py @@ -26,8 +26,6 @@ class OBJECT_PT_transform(ObjectButtonsPanel): ob = context.object - - row = layout.row() row.column().itemR(ob, "location") diff --git a/release/scripts/ui/buttons_scene.py b/release/scripts/ui/buttons_scene.py index 9bd0019bd6c..2b153737be3 100644 --- a/release/scripts/ui/buttons_scene.py +++ b/release/scripts/ui/buttons_scene.py @@ -474,7 +474,7 @@ class SCENE_PT_keying_sets(SceneButtonsPanel): scene = context.scene row = layout.row() - row.itemL(text="Keying Sets") + row.itemL(text="Keying Sets:") row = layout.row() @@ -512,7 +512,7 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel): ks = scene.active_keying_set row = layout.row() - row.itemL(text="Paths") + row.itemL(text="Paths:") row = layout.row() diff --git a/release/scripts/ui/space_time.py b/release/scripts/ui/space_time.py index 696dcf18623..fdb01d5c216 100644 --- a/release/scripts/ui/space_time.py +++ b/release/scripts/ui/space_time.py @@ -100,7 +100,7 @@ class TIME_MT_frame(bpy.types.Menu): layout.itemS() sub = layout.row() - sub.active = tools.enable_auto_key + #sub.active = tools.enable_auto_key sub.itemM("TIME_MT_autokey") class TIME_MT_playback(bpy.types.Menu): diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a832cae161b..ae18d7cac01 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9912,6 +9912,24 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* put 2.50 compatibility code here until next subversion bump */ { + Object *ob; + + /* New variables for axis-angle rotations and/or quaternion rotations were added, and need proper initialisation */ + for (ob= main->object.first; ob; ob= ob->id.next) { + /* new variables for all objects */ + ob->quat[0]= 1.0f; + ob->rotAxis[1]= 1.0f; + + /* bones */ + if (ob->pose) { + bPoseChannel *pchan; + + for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) { + /* just need to initalise rotation axis properly... */ + pchan->rotAxis[1]= 1.0f; + } + } + } } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 7a457548623..bf3fd0f4cf1 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -565,7 +565,7 @@ void ANIM_OT_paste_driver_button (wmOperatorType *ot) } -/* Paste Driver Button Operator ------------------------ */ +/* Copy to Clipboard Button Operator ------------------------ */ static int copy_clipboard_button_exec(bContext *C, wmOperator *op) { @@ -579,9 +579,9 @@ static int copy_clipboard_button_exec(bContext *C, wmOperator *op) memset(&ptr, 0, sizeof(PointerRNA)); uiAnimContextProperty(C, &ptr, &prop, &index); - if (ptr.data && prop) { // && RNA_property_animateable(ptr.data, prop) + if (ptr.data && prop) { path= RNA_path_from_ID_to_property(&ptr, prop); - + if (path) { WM_clipboard_text_set(path, FALSE); MEM_freeN(path); @@ -597,15 +597,14 @@ void ANIM_OT_copy_clipboard_button(wmOperatorType *ot) /* identifiers */ ot->name= "Copy Data Path"; ot->idname= "ANIM_OT_copy_clipboard_button"; - ot->description= "Copy the rna data path to the clipboard."; + ot->description= "Copy the RNA data path for this property to the clipboard."; /* callbacks */ ot->exec= copy_clipboard_button_exec; - //op->poll= ??? // TODO: need to have some driver to be able to do this... + //op->poll= ??? // TODO: need to have some valid property before this can be done /* flags */ - ot->flag= 0; + ot->flag= OPTYPE_REGISTER; } - /* ************************************************** */ diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index afaa9e3f400..d1ac624ec6f 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -349,6 +349,7 @@ static int add_keyingset_button_exec (bContext *C, wmOperator *op) /* add path to this setting */ BKE_keyingset_add_destination(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME); + ks->active_path= BLI_countlist(&ks->paths); success= 1; /* free the temp path created */ @@ -1354,6 +1355,9 @@ int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet } break; } + + /* send notifiers for updates (this doesn't require context to work!) */ + WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); } } } @@ -1484,6 +1488,9 @@ int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet } break; } + + /* send notifiers for updates (this doesn't require context to work!) */ + WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); } } } diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index facda32a41e..ca7401c36be 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -309,10 +309,11 @@ void ui_but_anim_menu(bContext *C, uiBut *but) uiItemO(layout, "Remove from Keying Set", 0, "ANIM_OT_remove_keyingset_button"); } } - + uiItemS(layout); - uiItemBooleanO(layout, "Copy Data Path", 0, "ANIM_OT_copy_clipboard_button", "all", 1); - + + uiItemO(layout, "Copy Data Path", 0, "ANIM_OT_copy_clipboard_button"); + uiPupMenuEnd(C, pup); } } diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index 3c10375c14b..641137c010b 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -3939,6 +3939,7 @@ static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBa /* add a new path with the information obtained (only if valid) */ // TODO: what do we do with group name? for now, we don't supply one, and just let this use the KeyingSet name BKE_keyingset_add_destination(ks, id, NULL, path, array_index, flag, groupmode); + ks->active_path= BLI_countlist(&ks->paths); } break; case KEYINGSET_EDITMODE_REMOVE: @@ -3950,6 +3951,7 @@ static void do_outliner_keyingset_editop(SpaceOops *soops, KeyingSet *ks, ListBa /* free path's data */ // TODO: we probably need an API method for this if (ksp->rna_path) MEM_freeN(ksp->rna_path); + ks->active_path= 0; /* remove path from set */ BLI_freelinkN(&ks->paths, ksp); diff --git a/source/blender/makesrna/intern/rna_animation_api.c b/source/blender/makesrna/intern/rna_animation_api.c index 6af87335e02..5852c494936 100644 --- a/source/blender/makesrna/intern/rna_animation_api.c +++ b/source/blender/makesrna/intern/rna_animation_api.c @@ -54,6 +54,7 @@ static void rna_KeyingSet_add_destination(KeyingSet *keyingset, ReportList *repo /* if data is valid, call the API function for this */ if (keyingset) { BKE_keyingset_add_destination(keyingset, id, group_name, rna_path, array_index, flag, grouping_method); + keyingset->active_path= BLI_countlist(&keyingset->paths); } else { BKE_report(reports, RPT_ERROR, "Keying Set Destination could not be added."); From ab287786b1e94d6b38ffda3d595ef90c664d78fe Mon Sep 17 00:00:00 2001 From: Andrea Weikert Date: Thu, 8 Oct 2009 12:13:23 +0000 Subject: [PATCH 033/138] 2.5 MSVC projectfiles_vc9 eek, forgot to add file in last commit --- .../blender/render/BRE_raytrace.vcproj | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 projectfiles_vc9/blender/render/BRE_raytrace.vcproj diff --git a/projectfiles_vc9/blender/render/BRE_raytrace.vcproj b/projectfiles_vc9/blender/render/BRE_raytrace.vcproj new file mode 100644 index 00000000000..95a5f2f92fd --- /dev/null +++ b/projectfiles_vc9/blender/render/BRE_raytrace.vcproj @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8056d27bac7e8c1122af5d854c6f0aefc7de5b55 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 12:33:51 +0000 Subject: [PATCH 034/138] Alt+A in the sequencer now redraws other sequencer views, not ideal but ok for now. --- source/blender/editors/screen/screen_ops.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index ad0218f3b80..8d8c2eba2a8 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2347,7 +2347,14 @@ static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event) ED_screen_animation_timer_update(C, stime->redraws); } else { - ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, sync, mode); + int redraws = TIME_REGION|TIME_ALL_3D_WIN; + + /* XXX - would like a better way to deal with this situation - Campbell */ + if((sa) && (sa->spacetype == SPACE_SEQ)) { + redraws |= TIME_SEQ; + } + + ED_screen_animation_timer(C, redraws, sync, mode); if(screen->animtimer) { wmTimer *wt= screen->animtimer; From b8354a2da84c997dc03d3b3fb2ce327653de320c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 14:11:06 +0000 Subject: [PATCH 035/138] unselected group color was too hard to see in the 3D view, made darker --- source/blender/editors/interface/resources.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index ee7db07f3c8..26a50cc3c24 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -456,7 +456,7 @@ void ui_theme_init_userdef(void) SETCOL(btheme->tv3d.lamp, 0, 0, 0, 40); SETCOL(btheme->tv3d.select, 241, 88, 0, 255); SETCOL(btheme->tv3d.active, 255, 140, 25, 255); - SETCOL(btheme->tv3d.group, 16, 64, 16, 255); + SETCOL(btheme->tv3d.group, 8, 48, 8, 255); SETCOL(btheme->tv3d.group_active, 85, 187, 85, 255); SETCOL(btheme->tv3d.transform, 0xff, 0xff, 0xff, 255); SETCOL(btheme->tv3d.vertex, 0, 0, 0, 255); @@ -1018,7 +1018,7 @@ void init_userdef_do_versions(void) } /* Group theme colors */ if(btheme->tv3d.group[3]==0) { - SETCOL(btheme->tv3d.group, 0x10, 0x40, 0x10, 255); + SETCOL(btheme->tv3d.group, 0x0C, 0x30, 0x0C, 255); SETCOL(btheme->tv3d.group_active, 0x66, 0xFF, 0x66, 255); } /* Sequence editor theme*/ From 248de36c63a51a600303aba74bbf7b188a90fd95 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Thu, 8 Oct 2009 15:02:01 +0000 Subject: [PATCH 036/138] netrender: bugfix by matd on irc. unbound var when broadcast is off --- release/scripts/io/netrender/master.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py index be23fda7a91..1c83e758ce5 100644 --- a/release/scripts/io/netrender/master.py +++ b/release/scripts/io/netrender/master.py @@ -744,7 +744,7 @@ def runMaster(address, broadcast, path, update_stats, test_break): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) - start_time = time.time() + start_time = time.time() while not test_break(): httpd.handle_request() From e936c809851ee99736827ecb6935ffb2cc06da9b Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Thu, 8 Oct 2009 15:19:57 +0000 Subject: [PATCH 037/138] Smoke: * Bugfix for non initialized arrays (reported by nudelZ) --- source/blender/blenkernel/intern/smoke.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index c1e79651c59..fbc052db6f3 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -964,8 +964,7 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) for(z = 0; z < sds->res[2]; z++) { EffectedPoint epoint; - float voxelCenter[3], vel[3], retvel[3]; - + float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0}; unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); if(density[index] < FLT_EPSILON) @@ -983,9 +982,9 @@ static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); // TODO dg - do in force! - force_x[index] += MIN2(MAX2(-1.0, retvel[0] * 0.002), 1.0); - force_y[index] += MIN2(MAX2(-1.0, retvel[1] * 0.002), 1.0); - force_z[index] += MIN2(MAX2(-1.0, retvel[2] * 0.002), 1.0); + force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); + force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); + force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0); } } From 88613b9184c2df08a2de58263b8f8e948543a0a1 Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Thu, 8 Oct 2009 15:28:31 +0000 Subject: [PATCH 038/138] Cocoa port : Bug fix : newly created window not seen as activated by WM Added more conservative memory management (may need to optimize later) --- intern/ghost/intern/GHOST_SystemCocoa.mm | 6 ++++-- intern/ghost/intern/GHOST_WindowCocoa.mm | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index fe3cd80f265..94ed5c7c2ac 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -806,7 +806,10 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( GHOST_ASSERT(m_windowManager, "m_windowManager not initialized"); m_windowManager->addWindow(window); m_windowManager->setActiveWindow(window); - pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + //Need to tell window manager the new window is the active one (Cocoa does not send the event activate upon window creation) + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowActivate, window)); + pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowSize, window)); + } else { GHOST_PRINT("GHOST_SystemCocoa::createWindow(): window invalid\n"); @@ -1156,7 +1159,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) GHOST_IWindow* window = m_windowManager->getActiveWindow(); if (!window) { - printf("\nM invalid window"); return GHOST_kFailure; } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 4d117d25df3..a185aa036b1 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -319,7 +319,7 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa() /*if(ugly_hack==m_windowRef) ugly_hack= NULL; if(ugly_hack==NULL) setDrawingContextType(GHOST_kDrawingContextTypeNone);*/ - + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [m_openGLView release]; if (m_window) { @@ -327,6 +327,7 @@ GHOST_WindowCocoa::~GHOST_WindowCocoa() [m_window release]; m_window = nil; } + [pool drain]; } #pragma mark accessors @@ -566,7 +567,9 @@ GHOST_TSuccess GHOST_WindowCocoa::swapBuffers() { if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [m_openGLContext flushBuffer]; + [pool drain]; return GHOST_kSuccess; } } @@ -577,7 +580,9 @@ GHOST_TSuccess GHOST_WindowCocoa::updateDrawingContext() { if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [m_openGLContext update]; + [pool drain]; return GHOST_kSuccess; } } @@ -588,6 +593,8 @@ GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() { if (m_drawingContextType == GHOST_kDrawingContextTypeOpenGL) { if (m_openGLContext != nil) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_openGLContext makeCurrentContext]; #ifdef GHOST_DRAW_CARBON_GUTTER // Restrict drawing to non-gutter area @@ -603,6 +610,7 @@ GHOST_TSuccess GHOST_WindowCocoa::activateDrawingContext() }; GLboolean result = ::aglSetInteger(m_aglCtx, AGL_BUFFER_RECT, b); #endif //GHOST_DRAW_CARBON_GUTTER + [pool drain]; return GHOST_kSuccess; } } From 66634e2be41be8530bec49b3bab27dfa4ea176d3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 15:29:43 +0000 Subject: [PATCH 039/138] toggle buttons for texture channels (hardcoded like UV layer buttons) --- source/blender/editors/interface/interface_templates.c | 4 ++++ source/blender/makesrna/intern/rna_material.c | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 5b93f9ee06d..d94d2be3a94 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2070,6 +2070,10 @@ ListBase uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, char *pr uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, &itemptr, "active_render", 0, 0, 0, 0, 0, NULL); uiBlockSetEmboss(block, UI_EMBOSS); } + else if (itemptr.type == &RNA_MaterialTextureSlot) { + uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0, NULL); + } + /* XXX - end hardcoded cruft */ if(name) MEM_freeN(name); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 28fcc3103b8..b22b5916362 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -1730,6 +1730,13 @@ void RNA_def_material(BlenderRNA *brna) rna_def_mtex_common(srna, "rna_Material_mtex_begin", "rna_Material_active_texture_get", "rna_Material_active_texture_set", "MaterialTextureSlot", "rna_Material_update"); + /* only material has this one */ + prop= RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "septex", 1); + RNA_def_property_array(prop, 18); + RNA_def_property_ui_text(prop, "Use Textures", "Enable/Disable each texture."); + RNA_def_property_update(prop, 0, "rna_Material_update"); + rna_def_material_colors(srna); rna_def_material_diffuse(srna); rna_def_material_specularity(srna); From ff07676b4047719236186e605d6578e1816b6cdc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 15:50:42 +0000 Subject: [PATCH 040/138] bring back automerge - [#19538] automerge editing doesn't work --- source/blender/editors/mesh/editmesh_mods.c | 34 +++++++++++-------- source/blender/editors/mesh/mesh_intern.h | 2 +- .../editors/transform/transform_conversions.c | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index a23a6dde652..4c9f63f910c 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -117,22 +117,26 @@ void EM_select_mirrored(Object *obedit, EditMesh *em) } } -void EM_automerge(int update) +void EM_automerge(Scene *scene, Object *obedit, int update) { -// XXX int len; - -// if ((scene->automerge) && -// (obedit && obedit->type==OB_MESH) && -// (((Mesh*)obedit->data)->mr==NULL) -// ) { -// len = removedoublesflag(1, 1, scene->toolsettings->doublimit); -// if (len) { -// em->totvert -= len; /* saves doing a countall */ -// if (update) { -// DAG_id_flush_update(obedit->data, OB_RECALC_DATA); -// } -// } -// } + Mesh *me= (Mesh*)obedit->data; /* can be NULL */ + int len; + + if ((scene->toolsettings->automerge) && + (obedit && obedit->type==OB_MESH && obedit->mode==OB_MODE_EDIT) && + (me->mr==NULL) + ) { + Mesh *me= (Mesh*)obedit->data; + EditMesh *em= me->edit_mesh; + + len = removedoublesflag(em, 1, 1, scene->toolsettings->doublimit); + if (len) { + em->totvert -= len; /* saves doing a countall */ + if (update) { + DAG_id_flush_update(obedit->data, OB_RECALC_DATA); + } + } + } } /* ****************************** SELECTION ROUTINES **************** */ diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 37a6d0f384f..7ee7fe1ebde 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -167,7 +167,7 @@ void MESH_OT_vertices_smooth(struct wmOperatorType *ot); void MESH_OT_flip_normals(struct wmOperatorType *ot); extern EditEdge *findnearestedge(ViewContext *vc, int *dist); -extern void EM_automerge(int update); +extern void EM_automerge(Scene *scene, Object *obedit, int update); void editmesh_select_by_material(EditMesh *em, int index); void righthandfaces(EditMesh *em, int select); /* makes faces righthand turning */ void EM_select_more(EditMesh *em); diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index a9c3e4676a0..51ce87803fd 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -4477,8 +4477,8 @@ void special_aftertrans_update(TransInfo *t) if (t->spacetype==SPACE_VIEW3D) { if (t->obedit) { if (cancelled==0) { + EM_automerge(t->scene, t->obedit, 1); #if 0 // TRANSFORM_FIX_ME - EM_automerge(1); /* when snapping, delay retopo until after automerge */ if (G.qual & LR_CTRLKEY) { retopo_do_all(); From d01c737283fddac411904a3d469495da71c48cd2 Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Thu, 8 Oct 2009 17:13:57 +0000 Subject: [PATCH 041/138] Cocoa port : Quick&dirty bug fix to catch ad discard tablet induced exceptions. I'll make a clean fix upon getting a tablet to debug. --- intern/ghost/intern/GHOST_SystemCocoa.mm | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 94ed5c7c2ac..7f98f67a1ba 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1098,7 +1098,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr) NSUInteger tabletEvent; //Handle tablet events combined with mouse events - switch ([event subtype]) { + @try { + switch ([event subtype]) { case NX_SUBTYPE_TABLET_POINT: tabletEvent = NSTabletPoint; break; @@ -1109,7 +1110,13 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr) default: tabletEvent = [event type]; break; + } } + @catch (NSException * e) { + //FIXME: check why we get such exceptions when using a tablet + return GHOST_kFailure; + } + switch (tabletEvent) { case NSTabletPoint: From e0c5e484732bb344fb845acc2678777e4bff1d5c Mon Sep 17 00:00:00 2001 From: Ken Hughes Date: Thu, 8 Oct 2009 17:32:51 +0000 Subject: [PATCH 042/138] Scripts ------- Port of MDD export script to Blender 2.5. --- release/scripts/io/export_mdd.py | 188 +++++++++++++++++++++++++++++++ release/scripts/ui/space_info.py | 1 + 2 files changed, 189 insertions(+) create mode 100644 release/scripts/io/export_mdd.py diff --git a/release/scripts/io/export_mdd.py b/release/scripts/io/export_mdd.py new file mode 100644 index 00000000000..f0e366ea505 --- /dev/null +++ b/release/scripts/io/export_mdd.py @@ -0,0 +1,188 @@ +#!BPY + +""" + Name: 'Vertex Keyframe Animation (.mdd)...' + Blender: 242 + Group: 'Export' + Tooltip: 'Animated mesh to MDD vertex keyframe file.' +""" + +__author__ = "Bill L.Nieuwendorp" +__bpydoc__ = """\ +This script Exports Lightwaves MotionDesigner format. + +The .mdd format has become quite a popular Pipeline format
+for moving animations from package to package. + +Be sure not to use modifiers that change the number or order of verts in the mesh +""" +#Please send any fixes,updates,bugs to Slow67_at_Gmail.com or cbarton_at_metavr.com +#Bill Niewuendorp +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ***** END GPL LICENCE BLOCK ***** + +import bpy +import Mathutils +import math +import os + +#import Blender +#from Blender import * +#import BPyMessages +try: + from struct import pack +except: + pack = None + +def zero_file(filepath): + ''' + If a file fails, this replaces it with 1 char, better not remove it? + ''' + file = open(filepath, 'w') + file.write('\n') # apparently macosx needs some data in a blank file? + file.close() + +def check_vertcount(mesh,vertcount): + ''' + check and make sure the vertcount is consistent throughout the frame range + ''' + if len(mesh.verts) != vertcount: + raise Exception('Error, number of verts has changed during animation, cannot export') + f.close() + zero_file(filepath) + return + + +def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS): + if not pack: + raise Exception('Error, this script requires the "pack" module') + + if ob.type != 'MESH': + raise Exception('Error, active object is not a mesh') + """ + Window.EditMode(0) + Blender.Window.WaitCursor(1) + + mesh_orig = Mesh.New() + mesh_orig.getFromObject(ob.name) + """ + orig_frame = sce.current_frame + sce.set_frame(PREF_STARTFRAME) + me = ob.create_mesh(True, 'PREVIEW') + + #Flip y and z + mat_flip= Mathutils.Matrix(\ + [1.0, 0.0, 0.0, 0.0],\ + [0.0, 0.0, 1.0, 0.0],\ + [0.0, 1.0, 0.0, 0.0],\ + [0.0, 0.0, 0.0, 1.0],\ + ) + + numverts = len(me.verts) + + numframes = PREF_ENDFRAME-PREF_STARTFRAME+1 + PREF_FPS= float(PREF_FPS) + f = open(filename, 'wb') #no Errors yet:Safe to create file + + # Write the header + f.write(pack(">2i", numframes, numverts)) + + # Write the frame times (should we use the time IPO??) + f.write( pack(">%df" % (numframes), *[frame/PREF_FPS for frame in range(numframes)]) ) # seconds + + #rest frame needed to keep frames in sync + """ + Blender.Set('curframe', PREF_STARTFRAME) + me_tmp.getFromObject(ob.name) + """ + + check_vertcount(me,numverts) + me.transform(mat_flip * ob.matrix) + f.write(pack(">%df" % (numverts*3), *[axis for v in me.verts for axis in v.co])) + + for frame in range(PREF_STARTFRAME,PREF_ENDFRAME+1):#in order to start at desired frame + """ + Blender.Set('curframe', frame) + me_tmp.getFromObject(ob.name) + """ + + sce.set_frame(frame) + me = ob.create_mesh(True, 'PREVIEW') + check_vertcount(me,numverts) + me.transform(mat_flip * ob.matrix) + + # Write the vertex data + f.write(pack(">%df" % (numverts*3), *[axis for v in me.verts for axis in v.co])) + + """ + me_tmp.verts= None + """ + f.close() + + print ('MDD Exported: %s frames:%d\n'% (filename, numframes-1)) + """ + Blender.Window.WaitCursor(0) + Blender.Set('curframe', orig_frame) + """ + sce.set_frame(orig_frame) + +class EXPORT_OT_mdd(bpy.types.Operator): + '''Animated mesh to MDD vertex keyframe file.''' + __idname__ = "export.mdd" + __label__ = "Export MDD" + + # get first scene to get min and max properties for frames, fps + + sce = bpy.data.scenes[bpy.data.scenes.keys()[0]] + minframe = sce.rna_type.properties["current_frame"].soft_min + maxframe = sce.rna_type.properties["current_frame"].soft_max + minfps = sce.render_data.rna_type.properties["fps"].soft_min + maxfps = sce.render_data.rna_type.properties["fps"].soft_max + + # List of operator properties, the attributes will be assigned + # to the class instance from the operator settings before calling. + __props__ = [ + bpy.props.StringProperty(attr="path", name="File Path", description="File path used for exporting the MDD file", maxlen= 1024, default= "tmp.mdd"), + bpy.props.IntProperty(attr="fps", name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default= 25), + bpy.props.IntProperty(attr="start_frame", name="Start Frame", description="Start frame for baking", min=minframe,max=maxframe,default=1), + bpy.props.IntProperty(attr="end_frame", name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default= 250), + ] + + def poll(self, context): + return context.active_object != None + + def execute(self, context): + if not self.path: + raise Exception("filename not set") + write(self.path, context.scene, context.active_object, + self.start_frame, self.end_frame, self.fps ) + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + +bpy.ops.add(EXPORT_OT_mdd) + +if __name__=='__main__': + #if not pack: +# Draw.PupMenu('Error%t|This script requires a full python install') + #Blender.Window.FileSelector(mdd_export_ui, 'EXPORT MDD', sys.makename(ext='.mdd')) + bpy.ops.EXPORT_OT_mdd(path="/tmp/test.mdd") + diff --git a/release/scripts/ui/space_info.py b/release/scripts/ui/space_info.py index 49261981ac2..3805a7d0dec 100644 --- a/release/scripts/ui/space_info.py +++ b/release/scripts/ui/space_info.py @@ -98,6 +98,7 @@ class INFO_MT_file_export(bpy.types.Menu): layout.itemO("export.3ds", text="3DS") layout.itemO("export.fbx", text="FBX") layout.itemO("export.obj", text="OBJ") + layout.itemO("export.mdd", text="MDD") layout.itemO("export.ply", text="PLY") layout.itemO("export.x3d", text="X3D") From 3ebd58673fb9a8c5ef13048b2e8e8a4cb7bb3a4e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 8 Oct 2009 18:40:03 +0000 Subject: [PATCH 043/138] Key Configuration Keymaps are now saveable and configurable from the user preferences, note that editing one item in a keymap means the whole keymap is now defined by the user and will not be updated by Blender, an option for syncing might be added later. The outliner interface is still there, but I will probably remove it. There's actually 3 levels now: * Default builtin key configuration. * Key configuration loaded from .py file, for configs like Blender 2.4x or other 3D applications. * Keymaps edited by the user and saved in .B.blend. These can be saved to .py files as well to make creating distributable configurations easier. Also, user preferences sections were reorganized a bit, now there is: Interface, Editing, Input, Files and System. Implementation notes: * wmKeyConfig was added which represents a key configuration containing keymaps. * wmKeymapItem was renamed to wmKeyMapItem for consistency with wmKeyMap. * Modal maps are not wrapped yet. * User preferences DNA file reading did not support newdataadr() yet, added this now for reading keymaps. * Key configuration related settings are now RNA wrapped. * is_property_set and is_property_hidden python methods were added. --- release/scripts/ui/space_userpref.py | 367 +++++++++++++++-- source/blender/blenkernel/BKE_screen.h | 5 +- source/blender/blenkernel/intern/blender.c | 17 + source/blender/blenloader/intern/readfile.c | 96 +++-- source/blender/blenloader/intern/writefile.c | 16 +- .../editors/animation/anim_channels_edit.c | 4 +- .../blender/editors/animation/anim_markers.c | 4 +- source/blender/editors/animation/anim_ops.c | 4 +- .../blender/editors/armature/armature_ops.c | 8 +- source/blender/editors/curve/curve_ops.c | 6 +- source/blender/editors/gpencil/gpencil_ops.c | 6 +- source/blender/editors/include/ED_anim_api.h | 6 +- source/blender/editors/include/ED_armature.h | 4 +- source/blender/editors/include/ED_curve.h | 4 +- source/blender/editors/include/ED_gpencil.h | 4 +- source/blender/editors/include/ED_markers.h | 4 +- source/blender/editors/include/ED_mball.h | 4 +- source/blender/editors/include/ED_mesh.h | 5 +- source/blender/editors/include/ED_object.h | 4 +- source/blender/editors/include/ED_particle.h | 2 +- source/blender/editors/include/ED_physics.h | 4 +- source/blender/editors/include/ED_screen.h | 5 +- source/blender/editors/include/ED_sculpt.h | 4 +- source/blender/editors/include/ED_transform.h | 3 +- source/blender/editors/include/ED_uvedit.h | 4 +- source/blender/editors/include/UI_interface.h | 3 + source/blender/editors/include/UI_view2d.h | 4 +- source/blender/editors/interface/interface.c | 11 +- .../editors/interface/interface_handlers.c | 16 +- .../editors/interface/interface_layout.c | 38 +- .../editors/interface/interface_utils.c | 4 +- source/blender/editors/interface/view2d_ops.c | 6 +- source/blender/editors/mesh/editmesh_mods.c | 52 ++- source/blender/editors/mesh/mesh_ops.c | 6 +- source/blender/editors/metaball/mball_ops.c | 4 +- source/blender/editors/object/object_ops.c | 10 +- source/blender/editors/physics/physics_ops.c | 10 +- source/blender/editors/screen/area.c | 12 +- source/blender/editors/screen/screen_ops.c | 18 +- .../blender/editors/sculpt_paint/paint_ops.c | 10 +- .../editors/space_action/action_intern.h | 2 +- .../blender/editors/space_action/action_ops.c | 12 +- .../editors/space_action/space_action.c | 4 +- source/blender/editors/space_api/spacetypes.c | 36 +- .../editors/space_buttons/space_buttons.c | 6 +- .../editors/space_console/space_console.c | 6 +- .../blender/editors/space_file/file_panels.c | 12 +- source/blender/editors/space_file/filelist.c | 2 +- source/blender/editors/space_file/filesel.c | 32 +- .../blender/editors/space_file/space_file.c | 20 +- .../editors/space_graph/graph_intern.h | 2 +- .../blender/editors/space_graph/graph_ops.c | 14 +- .../blender/editors/space_graph/space_graph.c | 10 +- .../blender/editors/space_image/space_image.c | 16 +- .../blender/editors/space_info/space_info.c | 2 +- .../blender/editors/space_logic/space_logic.c | 8 +- source/blender/editors/space_nla/nla_intern.h | 2 +- source/blender/editors/space_nla/nla_ops.c | 20 +- source/blender/editors/space_nla/space_nla.c | 10 +- .../blender/editors/space_node/node_intern.h | 2 +- source/blender/editors/space_node/node_ops.c | 8 +- .../blender/editors/space_node/space_node.c | 2 +- .../blender/editors/space_outliner/outliner.c | 28 +- .../editors/space_outliner/outliner_intern.h | 2 +- .../editors/space_outliner/outliner_ops.c | 4 +- .../editors/space_outliner/space_outliner.c | 2 +- .../editors/space_script/script_intern.h | 2 +- .../blender/editors/space_script/script_ops.c | 4 +- .../editors/space_script/space_script.c | 2 +- .../space_sequencer/sequencer_intern.h | 5 +- .../editors/space_sequencer/sequencer_ops.c | 8 +- .../editors/space_sequencer/space_sequencer.c | 2 +- .../blender/editors/space_sound/space_sound.c | 4 +- .../blender/editors/space_text/space_text.c | 6 +- .../blender/editors/space_time/space_time.c | 2 +- .../blender/editors/space_time/time_intern.h | 2 +- source/blender/editors/space_time/time_ops.c | 4 +- .../editors/space_userpref/space_userpref.c | 4 +- .../editors/space_view3d/space_view3d.c | 42 +- .../editors/space_view3d/view3d_edit.c | 18 +- .../editors/space_view3d/view3d_intern.h | 10 +- .../blender/editors/space_view3d/view3d_ops.c | 18 +- .../editors/space_view3d/view3d_view.c | 6 +- source/blender/editors/transform/transform.c | 6 +- source/blender/editors/transform/transform.h | 2 +- .../blender/editors/transform/transform_ops.c | 6 +- source/blender/editors/uvedit/uvedit_ops.c | 6 +- source/blender/makesdna/DNA_userdef_types.h | 10 + .../makesdna/DNA_windowmanager_types.h | 65 ++- source/blender/makesrna/RNA_access.h | 30 +- source/blender/makesrna/RNA_types.h | 3 + source/blender/makesrna/intern/rna_access.c | 5 +- source/blender/makesrna/intern/rna_define.c | 1 + source/blender/makesrna/intern/rna_internal.h | 3 +- source/blender/makesrna/intern/rna_ui_api.c | 6 +- source/blender/makesrna/intern/rna_userdef.c | 94 ++--- source/blender/makesrna/intern/rna_wm.c | 383 +++++++++++++++++- source/blender/makesrna/intern/rna_wm_api.c | 74 +++- source/blender/python/intern/bpy_rna.c | 31 +- source/blender/windowmanager/WM_api.h | 34 +- source/blender/windowmanager/intern/wm.c | 36 +- .../windowmanager/intern/wm_event_system.c | 17 +- .../blender/windowmanager/intern/wm_keymap.c | 328 +++++++++++---- .../windowmanager/intern/wm_operators.c | 41 +- .../blender/windowmanager/intern/wm_window.c | 8 +- source/blender/windowmanager/wm.h | 2 +- .../blender/windowmanager/wm_event_system.h | 1 - source/blender/windowmanager/wm_event_types.h | 12 +- 108 files changed, 1763 insertions(+), 638 deletions(-) diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index 43c70dac4b1..ff4461db02f 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -12,6 +12,10 @@ class USERPREF_HT_header(bpy.types.Header): layout.operator_context = "EXEC_AREA" layout.itemO("wm.save_homefile", text="Save As Default") + + if userpref.active_section == 'INPUT': + layout.operator_context = "INVOKE_DEFAULT" + layout.itemO("wm.keyconfig_save", "Save Key Configuration...") class USERPREF_MT_view(bpy.types.Menu): __space_type__ = 'USER_PREFERENCES' @@ -31,14 +35,14 @@ class USERPREF_PT_tabs(bpy.types.Panel): layout.itemR(userpref, "active_section", expand=True) -class USERPREF_PT_view(bpy.types.Panel): +class USERPREF_PT_interface(bpy.types.Panel): __space_type__ = 'USER_PREFERENCES' - __label__ = "View" + __label__ = "Interface" __show_header__ = False def poll(self, context): userpref = context.user_preferences - return (userpref.active_section == 'VIEW_CONTROLS') + return (userpref.active_section == 'INTERFACE') def draw(self, context): layout = self.layout @@ -87,37 +91,27 @@ class USERPREF_PT_view(bpy.types.Panel): sub1.itemR(view, "perspective_orthographic_switch") sub1.itemR(view, "smooth_view") sub1.itemR(view, "rotation_angle") - sub1.itemS() - sub1.itemL(text="NDOF Device:") - sub1.itemR(view, "ndof_pan_speed", text="Pan Speed") - sub1.itemR(view, "ndof_rotate_speed", text="Orbit Speed") col = split.column() sub = col.split(percentage=0.85) sub1 = sub.column() - sub1.itemL(text="Mouse Buttons:") - - sub2 = sub1.column() - sub2.enabled = (view.select_mouse == 'RIGHT') - sub2.itemR(view, "emulate_3_button_mouse") - sub1.itemL(text="Select With:") - sub1.row().itemR(view, "select_mouse", expand=True) - sub1.itemL(text="Middle Mouse:") - sub1.row().itemR(view, "middle_mouse", expand=True) - sub1.itemR(view, "use_middle_mouse_paste") - sub1.itemL(text="Mouse Wheel:") - sub1.itemR(view, "wheel_invert_zoom", text="Invert Zoom") - sub1.itemR(view, "wheel_scroll_lines", text="Scroll Lines") - sub1.itemL(text="Mouse Motion:") - sub1.itemR(view, "continuous_mouse", text="Continuous Grab") - sub1.itemS() sub1.itemL(text="Menus:") sub1.itemR(view, "open_mouse_over") sub1.itemL(text="Menu Open Delay:") sub1.itemR(view, "open_toplevel_delay", text="Top Level") sub1.itemR(view, "open_sublevel_delay", text="Sub Level") + sub1.itemS() + sub1.itemS() + sub1.itemS() + + sub1.itemL(text="Toolbox:") + sub1.itemR(view, "use_column_layout") + sub1.itemL(text="Open Toolbox Delay:") + sub1.itemR(view, "open_left_mouse_delay", text="Hold LMB") + sub1.itemR(view, "open_right_mouse_delay", text="Hold RMB") + col = split.column() sub = col.split(percentage=0.85) @@ -129,14 +123,6 @@ class USERPREF_PT_view(bpy.types.Panel): sub2.itemR(view, "manipulator_size", text="Size") sub2.itemR(view, "manipulator_handle_size", text="Handle Size") sub2.itemR(view, "manipulator_hotspot", text="Hotspot") - sub1.itemS() - sub1.itemS() - sub1.itemS() - sub1.itemL(text="Toolbox:") - sub1.itemR(view, "use_column_layout") - sub1.itemL(text="Open Toolbox Delay:") - sub1.itemR(view, "open_left_mouse_delay", text="Hold LMB") - sub1.itemR(view, "open_right_mouse_delay", text="Hold RMB") class USERPREF_PT_edit(bpy.types.Panel): __space_type__ = 'USER_PREFERENCES' @@ -145,7 +131,7 @@ class USERPREF_PT_edit(bpy.types.Panel): def poll(self, context): userpref = context.user_preferences - return (userpref.active_section == 'EDIT_METHODS') + return (userpref.active_section == 'EDITING') def draw(self, context): layout = self.layout @@ -248,7 +234,7 @@ class USERPREF_PT_system(bpy.types.Panel): def poll(self, context): userpref = context.user_preferences - return (userpref.active_section == 'SYSTEM_OPENGL') + return (userpref.active_section == 'SYSTEM') def draw(self, context): layout = self.layout @@ -276,7 +262,7 @@ class USERPREF_PT_system(bpy.types.Panel): sub1.itemL(text="Sound:") sub1.row().itemR(system, "audio_device", expand=True) sub2 = sub1.column() - sub2.active = system.audio_device != 'AUDIO_DEVICE_NULL' + sub2.active = system.audio_device != 'NONE' sub2.itemR(system, "enable_all_codecs") sub2.itemR(system, "game_sound") sub2.itemR(system, "audio_channels", text="Channels") @@ -332,14 +318,14 @@ class USERPREF_PT_system(bpy.types.Panel): sub1.itemR(system, "prefetch_frames") sub1.itemR(system, "memory_cache_limit") -class USERPREF_PT_filepaths(bpy.types.Panel): +class USERPREF_PT_file(bpy.types.Panel): __space_type__ = 'USER_PREFERENCES' - __label__ = "File Paths" + __label__ = "Files" __show_header__ = False def poll(self, context): userpref = context.user_preferences - return (userpref.active_section == 'FILE_PATHS') + return (userpref.active_section == 'FILES') def draw(self, context): layout = self.layout @@ -398,11 +384,314 @@ class USERPREF_PT_filepaths(bpy.types.Panel): sub3.enabled = paths.auto_save_temporary_files sub3.itemR(paths, "auto_save_time", text="Timer (mins)") +class USERPREF_PT_input(bpy.types.Panel): + __space_type__ = 'USER_PREFERENCES' + __label__ = "Input" + __show_header__ = False + + def poll(self, context): + userpref = context.user_preferences + return (userpref.active_section == 'INPUT') + + def draw(self, context): + layout = self.layout + + userpref = context.user_preferences + wm = context.manager + #input = userpref.input + input = userpref + view = userpref.view + + split = layout.split(percentage=0.25) + + # General settings + row = split.row() + col = row.column() + + sub = col.column() + sub.itemL(text="Configuration:") + sub.item_pointerR(wm, "active_keyconfig", wm, "keyconfigs", text="") + + col.itemS() + + sub = col.column() + sub.itemL(text="Mouse:") + sub1 = sub.column() + sub1.enabled = (view.select_mouse == 'RIGHT') + sub1.itemR(view, "emulate_3_button_mouse") + sub.itemR(view, "continuous_mouse", text="Continuous Grab") + + sub.itemL(text="Select With:") + sub.row().itemR(view, "select_mouse", expand=True) + #sub.itemL(text="Middle Mouse:") + #sub.row().itemR(view, "middle_mouse", expand=True) + #sub.itemR(view, "use_middle_mouse_paste") + + #col.itemS() + + #sub = col.column() + #sub.itemL(text="Mouse Wheel:") + #sub.itemR(view, "wheel_invert_zoom", text="Invert Zoom") + #sub.itemR(view, "wheel_scroll_lines", text="Scroll Lines") + + col.itemS() + + sub = col.column() + sub.itemL(text="NDOF Device:") + sub.itemR(view, "ndof_pan_speed", text="Pan Speed") + sub.itemR(view, "ndof_rotate_speed", text="Orbit Speed") + + row.itemS() + + # Keymap Settings + col = split.column() + + kc = wm.active_keyconfig + defkc = wm.default_keyconfig + km = wm.active_keymap + + subsplit = col.split() + subsplit.item_pointerR(wm, "active_keymap", defkc, "keymaps", text="Map:") + if km.user_defined: + row = subsplit.row() + row.itemO("WM_OT_keymap_restore", text="Restore") + row.item_booleanO("WM_OT_keymap_restore", "all", True, text="Restore All") + else: + row = subsplit.row() + row.itemO("WM_OT_keymap_edit", text="Edit") + row.itemL() + + col.itemS() + + for kmi in km.items: + subcol = col.column() + subcol.set_context_pointer("keyitem", kmi) + + row = subcol.row() + + if kmi.expanded: + row.itemR(kmi, "expanded", text="", icon="ICON_TRIA_DOWN") + else: + row.itemR(kmi, "expanded", text="", icon="ICON_TRIA_RIGHT") + + itemrow = row.row() + itemrow.enabled = km.user_defined + itemrow.itemR(kmi, "active", text="", icon="ICON_DOT") + + itemcol = itemrow.column() + itemcol.active = kmi.active + row = itemcol.row() + row.itemR(kmi, "idname", text="") + + sub = row.row() + sub.scale_x = 0.6 + sub.itemR(kmi, "map_type", text="") + + sub = row.row(align=True) + if kmi.map_type == 'KEYBOARD': + sub.itemR(kmi, "type", text="", full_event=True) + elif kmi.map_type == 'MOUSE': + sub.itemR(kmi, "type", text="", full_event=True) + elif kmi.map_type == 'TWEAK': + sub.scale_x = 0.5 + sub.itemR(kmi, "type", text="") + sub.itemR(kmi, "value", text="") + elif kmi.map_type == 'TIMER': + sub.itemR(kmi, "type", text="") + else: + sub.itemL() + + if kmi.expanded: + if kmi.map_type not in ('TEXTINPUT', 'TIMER'): + sub = itemcol.row(align=True) + + if kmi.map_type == 'KEYBOARD': + sub.itemR(kmi, "type", text="", event=True) + sub.itemR(kmi, "value", text="") + elif kmi.map_type == 'MOUSE': + sub.itemR(kmi, "type", text="") + sub.itemR(kmi, "value", text="") + else: + sub.itemL() + sub.itemL() + + subrow = sub.row() + subrow.scale_x = 0.75 + subrow.itemR(kmi, "shift") + subrow.itemR(kmi, "ctrl") + subrow.itemR(kmi, "alt") + subrow.itemR(kmi, "oskey") + sub.itemR(kmi, "key_modifier", text="", event=True) + + flow = itemcol.column_flow(columns=2) + props = kmi.properties + + if props != None: + for pname in dir(props): + if not props.is_property_hidden(pname): + flow.itemR(props, pname) + + itemcol.itemS() + + itemrow.itemO("wm.keyitem_remove", text="", icon="ICON_ZOOMOUT") + + itemrow = col.row() + itemrow.itemL() + itemrow.itemO("wm.keyitem_add", text="", icon="ICON_ZOOMIN") + itemrow.enabled = km.user_defined + bpy.types.register(USERPREF_HT_header) bpy.types.register(USERPREF_MT_view) bpy.types.register(USERPREF_PT_tabs) -bpy.types.register(USERPREF_PT_view) +bpy.types.register(USERPREF_PT_interface) bpy.types.register(USERPREF_PT_edit) bpy.types.register(USERPREF_PT_system) -bpy.types.register(USERPREF_PT_filepaths) +bpy.types.register(USERPREF_PT_file) +bpy.types.register(USERPREF_PT_input) + +class WM_OT_keyconfig_save(bpy.types.Operator): + "Save key configuration to a python script." + __idname__ = "wm.keyconfig_save" + __label__ = "Save Key Configuration..." + __props__ = [ + bpy.props.StringProperty(attr="path", name="File Path", description="File path to write file to.")] + + def _string_value(self, value): + result = "" + if isinstance(value, str): + if value != "": + result = "\'%s\'" % value + elif isinstance(value, bool): + if value: + result = "True" + else: + result = "False" + elif isinstance(value, float): + result = "%.10f" % value + elif isinstance(value, int): + result = "%d" % value + elif getattr(value, '__len__', False): + if len(value): + result = "[" + for i in range(0, len(value)): + result += self._string_value(value[i]) + if i != len(value)-1: + result += ", " + result += "]" + else: + print("Save key configuration: can't write ", value) + + return result + + def execute(self, context): + if not self.path: + raise Exception("File path not set.") + + f = open(self.path, "w") + if not f: + raise Exception("Could not open file.") + + wm = context.manager + kc = wm.active_keyconfig + + f.write('# Configuration %s\n' % kc.name) + + f.write("wm = bpy.data.windowmanagers[0]\n"); + f.write("kc = wm.add_keyconfig(\'%s\')\n\n" % kc.name) + + for km in kc.keymaps: + f.write("# Map %s\n" % km.name) + f.write("km = kc.add_keymap(\'%s\', space_type=\'%s\', region_type=\'%s\')\n\n" % (km.name, km.space_type, km.region_type)) + for kmi in km.items: + f.write("kmi = km.add_item(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, kmi.value)) + if kmi.shift: + f.write(", shift=True") + if kmi.ctrl: + f.write(", ctrl=True") + if kmi.alt: + f.write(", alt=True") + if kmi.oskey: + f.write(", oskey=True") + if kmi.key_modifier and kmi.key_modifier != 'NONE': + f.write(", key_modifier=\'%s\'" % kmi.key_modifier) + f.write(")\n") + + props = kmi.properties + + if props != None: + for pname in dir(props): + if props.is_property_set(pname) and not props.is_property_hidden(pname): + value = eval("props.%s" % pname) + value = self._string_value(value) + if value != "": + f.write("kmi.properties.%s = %s\n" % (pname, value)) + + f.write("\n") + + f.close() + + return ('FINISHED',) + + def invoke(self, context, event): + wm = context.manager + wm.add_fileselect(self.__operator__) + return ('RUNNING_MODAL',) + +class WM_OT_keymap_edit(bpy.types.Operator): + "Edit key map." + __idname__ = "wm.keymap_edit" + __label__ = "Edit Key Map" + + def execute(self, context): + wm = context.manager + km = wm.active_keymap + km.copy_to_user() + return ('FINISHED',) + +class WM_OT_keymap_restore(bpy.types.Operator): + "Restore key map" + __idname__ = "wm.keymap_restore" + __label__ = "Restore Key Map" + __props__ = [bpy.props.BoolProperty(attr="all", name="All Keymaps", description="Restore all keymaps to default.")] + + def execute(self, context): + wm = context.manager + + if self.all: + for km in wm.default_keyconfig.keymaps: + km.restore_to_default() + else: + km = wm.active_keymap + km.restore_to_default() + + return ('FINISHED',) + +class WM_OT_keyitem_add(bpy.types.Operator): + "Add key map item." + __idname__ = "wm.keyitem_add" + __label__ = "Add Key Map Item" + + def execute(self, context): + wm = context.manager + km = wm.active_keymap + kmi = km.add_item("", "A", "PRESS") + return ('FINISHED',) + +class WM_OT_keyitem_remove(bpy.types.Operator): + "Remove key map item." + __idname__ = "wm.keyitem_remove" + __label__ = "Remove Key Map Item" + + def execute(self, context): + wm = context.manager + kmi = context.keyitem + km = wm.active_keymap + km.remove_item(kmi) + return ('FINISHED',) + +bpy.ops.add(WM_OT_keyconfig_save) +bpy.ops.add(WM_OT_keymap_edit) +bpy.ops.add(WM_OT_keymap_restore) +bpy.ops.add(WM_OT_keyitem_add) +bpy.ops.add(WM_OT_keyitem_remove) diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index b983c6f7dc4..7c62c8c6dd4 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -44,6 +44,7 @@ struct SpaceType; struct wmNotifier; struct wmWindow; struct wmWindowManager; +struct wmKeyConfig; struct uiLayout; struct uiMenuItem; @@ -81,7 +82,7 @@ typedef struct SpaceType { /* register operator types on startup */ void (*operatortypes)(void); /* add default items to WM keymap */ - void (*keymap)(struct wmWindowManager *); + void (*keymap)(struct wmKeyConfig *); /* return context data */ int (*context)(const struct bContext *, const char*, struct bContextDataResult *); @@ -122,7 +123,7 @@ typedef struct ARegionType { /* register operator types on startup */ void (*operatortypes)(void); /* add own items to keymap */ - void (*keymap)(struct wmWindowManager *); + void (*keymap)(struct wmKeyConfig *); /* allows default cursor per region */ void (*cursor)(struct wmWindow *, struct ScrArea *, struct ARegion *ar); diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index f261b020717..2df5b7c173c 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -74,6 +74,7 @@ #include "BKE_displist.h" #include "BKE_font.h" #include "BKE_global.h" +#include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_ipo.h" #include "BKE_main.h" @@ -406,10 +407,26 @@ static int handle_subversion_warning(Main *main) void BKE_userdef_free(void) { + wmKeyMap *km; + wmKeyMapItem *kmi; + + for(km=U.keymaps.first; km; km=km->next) { + for(kmi=km->items.first; kmi; kmi=kmi->next) { + if(kmi->properties) { + IDP_FreeProperty(kmi->properties); + MEM_freeN(kmi->properties); + } + if(kmi->ptr) + MEM_freeN(kmi->ptr); + } + + BLI_freelistN(&km->items); + } BLI_freelistN(&U.uistyles); BLI_freelistN(&U.uifonts); BLI_freelistN(&U.themes); + BLI_freelistN(&U.keymaps); } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index ae18d7cac01..f2bf8b19bc6 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4446,11 +4446,13 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm) } wm->operators.first= wm->operators.last= NULL; - wm->keymaps.first= wm->keymaps.last= NULL; wm->paintcursors.first= wm->paintcursors.last= NULL; wm->queue.first= wm->queue.last= NULL; BKE_reports_init(&wm->reports, RPT_STORE); + wm->keyconfigs.first= wm->keyconfigs.last= NULL; + wm->defaultconf= NULL; + wm->jobs.first= wm->jobs.last= NULL; wm->windrawable= NULL; @@ -5276,6 +5278,33 @@ static char *dataname(short id_code) } +static BHead *read_data_into_oldnewmap(FileData *fd, BHead *bhead, char *allocname) +{ + bhead = blo_nextbhead(fd, bhead); + + while(bhead && bhead->code==DATA) { + void *data; +#if 0 + /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ + short *sp= fd->filesdna->structs[bhead->SDNAnr]; + char *allocname = fd->filesdna->types[ sp[0] ]; + char *tmp= malloc(100); + + strcpy(tmp, allocname); + data= read_struct(fd, bhead, tmp); +#endif + data= read_struct(fd, bhead, allocname); + + if (data) { + oldnewmap_insert(fd->datamap, bhead->old, data, 0); + } + + bhead = blo_nextbhead(fd, bhead); + } + + return bhead; +} + static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID **id_r) { /* this routine reads a libblock and its direct data. Use link functions @@ -5317,32 +5346,11 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID return blo_nextbhead(fd, bhead); } - bhead = blo_nextbhead(fd, bhead); - /* need a name for the mallocN, just for debugging and sane prints on leaks */ allocname= dataname(GS(id->name)); - /* read all data */ - - while(bhead && bhead->code==DATA) { - void *data; -#if 0 - /* XXX DUMB DEBUGGING OPTION TO GIVE NAMES for guarded malloc errors */ - short *sp= fd->filesdna->structs[bhead->SDNAnr]; - char *allocname = fd->filesdna->types[ sp[0] ]; - char *tmp= malloc(100); - - strcpy(tmp, allocname); - data= read_struct(fd, bhead, tmp); -#endif - data= read_struct(fd, bhead, allocname); - - if (data) { - oldnewmap_insert(fd->datamap, bhead->old, data, 0); - } - - bhead = blo_nextbhead(fd, bhead); - } + /* read all data into fd->datamap */ + bhead= read_data_into_oldnewmap(fd, bhead, allocname); /* init pointers direct data */ switch( GS(id->name) ) { @@ -9975,23 +9983,39 @@ static void lib_link_all(FileData *fd, Main *main) static BHead *read_userdef(BlendFileData *bfd, FileData *fd, BHead *bhead) { - Link *link; + UserDef *user; + wmKeyMap *keymap; + wmKeyMapItem *kmi; - bfd->user= read_struct(fd, bhead, "user def"); - bfd->user->themes.first= bfd->user->themes.last= NULL; - // XXX - bfd->user->uifonts.first= bfd->user->uifonts.last= NULL; - bfd->user->uistyles.first= bfd->user->uistyles.last= NULL; + bfd->user= user= read_struct(fd, bhead, "user def"); - bhead = blo_nextbhead(fd, bhead); + /* read all data into fd->datamap */ + bhead= read_data_into_oldnewmap(fd, bhead, "user def"); - /* read all attached data */ - while(bhead && bhead->code==DATA) { - link= read_struct(fd, bhead, "user def data"); - BLI_addtail(&bfd->user->themes, link); - bhead = blo_nextbhead(fd, bhead); + link_list(fd, &user->themes); + link_list(fd, &user->keymaps); + + for(keymap=user->keymaps.first; keymap; keymap=keymap->next) { + keymap->modal_items= NULL; + keymap->poll= NULL; + + link_list(fd, &keymap->items); + for(kmi=keymap->items.first; kmi; kmi=kmi->next) { + kmi->properties= newdataadr(fd, kmi->properties); + if(kmi->properties) + IDP_DirectLinkProperty(kmi->properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); + kmi->ptr= NULL; + } } + // XXX + user->uifonts.first= user->uifonts.last= NULL; + user->uistyles.first= user->uistyles.last= NULL; + + /* free fd->datamap again */ + oldnewmap_free_unused(fd->datamap); + oldnewmap_clear(fd->datamap); + return bhead; } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 25cbd4b65e7..e3d061d8e4b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -537,13 +537,23 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) /* for renderdeamon static void write_userdef(WriteData *wd) { bTheme *btheme; + wmKeyMap *keymap; + wmKeyMapItem *kmi; writestruct(wd, USER, "UserDef", 1, &U); - btheme= U.themes.first; - while(btheme) { + for(btheme= U.themes.first; btheme; btheme=btheme->next) writestruct(wd, DATA, "bTheme", 1, btheme); - btheme= btheme->next; + + for(keymap= U.keymaps.first; keymap; keymap=keymap->next) { + writestruct(wd, DATA, "wmKeyMap", 1, keymap); + + for(kmi=keymap->items.first; kmi; kmi=kmi->next) { + writestruct(wd, DATA, "wmKeyMapItem", 1, kmi); + + if(kmi->properties) + IDP_WriteProperty(kmi->properties, wd); + } } } diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 83f5fca5af5..7ee591f8cab 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1687,9 +1687,9 @@ void ED_operatortypes_animchannels(void) WM_operatortype_append(ANIM_OT_channels_visibility_toggle); } -void ED_keymap_animchannels(wmWindowManager *wm) +void ED_keymap_animchannels(wmKeyConfig *keyconf) { - wmKeyMap *keymap = WM_keymap_find(wm, "Animation_Channels", 0, 0); + wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation_Channels", 0, 0); /* selection */ /* click-select */ diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 6c44086af41..f4ecb9d5def 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -990,9 +990,9 @@ void ED_operatortypes_marker(void) } /* called in screen_ops.c:ED_keymap_screen() */ -void ED_marker_keymap(wmWindowManager *wm) +void ED_marker_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Markers", 0, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0); WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0); diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 83b2e2688c9..35eac6d23f1 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -416,9 +416,9 @@ void ED_operatortypes_anim(void) WM_operatortype_append(ANIM_OT_keying_set_path_remove); } -void ED_keymap_anim(wmWindowManager *wm) +void ED_keymap_anim(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Animation", 0, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Animation", 0, 0); /* frame management */ /* NOTE: 'ACTIONMOUSE' not 'LEFTMOUSE', as user may have swapped mouse-buttons */ diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index d465c1f8c9a..2bf414ef969 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -205,13 +205,13 @@ void ED_operatortypes_armature(void) WM_operatortype_append(ARMATURE_OT_test); // XXX temp test for context iterators... to be removed } -void ED_keymap_armature(wmWindowManager *wm) +void ED_keymap_armature(wmKeyConfig *keyconf) { wmKeyMap *keymap; - wmKeymapItem *kmi; + wmKeyMapItem *kmi; /* Armature ------------------------ */ - keymap= WM_keymap_find(wm, "Armature", 0, 0); + keymap= WM_keymap_find(keyconf, "Armature", 0, 0); keymap->poll= ED_operator_editarmature; /* only set in editmode armature, by space_view3d listener */ @@ -297,7 +297,7 @@ void ED_keymap_armature(wmWindowManager *wm) /* Pose ------------------------ */ /* only set in posemode, by space_view3d listener */ - keymap= WM_keymap_find(wm, "Pose", 0, 0); + keymap= WM_keymap_find(keyconf, "Pose", 0, 0); keymap->poll= ED_operator_posemode; // XXX: set parent is object-based operator, but it should also be available here... diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 77c5ed1de2c..a71ff8347e8 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -161,11 +161,11 @@ void ED_operatortypes_curve(void) WM_operatortype_append(CURVE_OT_specials_menu); } -void ED_keymap_curve(wmWindowManager *wm) +void ED_keymap_curve(wmKeyConfig *keyconf) { wmKeyMap *keymap; - keymap= WM_keymap_find(wm, "Font", 0, 0); + keymap= WM_keymap_find(keyconf, "Font", 0, 0); keymap->poll= ED_operator_editfont; /* only set in editmode font, by space_view3d listener */ @@ -215,7 +215,7 @@ void ED_keymap_curve(wmWindowManager *wm) WM_keymap_add_item(keymap, "FONT_OT_text_insert", KM_TEXTINPUT, KM_ANY, KM_ANY, 0); // last! /* only set in editmode curve, by space_view3d listener */ - keymap= WM_keymap_find(wm, "Curve", 0, 0); + keymap= WM_keymap_find(keyconf, "Curve", 0, 0); keymap->poll= ED_operator_editsurfcurve; WM_keymap_add_item(keymap, "OBJECT_OT_curve_add", AKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index d311b39b9a3..6237e193a13 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -45,10 +45,10 @@ /* ****************************************** */ /* Generic Editing Keymap */ -void ED_keymap_gpencil(wmWindowManager *wm) +void ED_keymap_gpencil(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Grease Pencil", 0, 0); - wmKeymapItem *kmi; + wmKeyMap *keymap= WM_keymap_find(keyconf, "Grease Pencil", 0, 0); + wmKeyMapItem *kmi; /* Draw */ /* draw */ diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index d9439956569..97f4dd915e4 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -34,7 +34,7 @@ struct ListBase; struct AnimData; struct bContext; -struct wmWindowManager; +struct wmKeyConfig; struct ScrArea; struct ARegion; struct View2D; @@ -487,11 +487,11 @@ void ANIM_pose_to_action_sync(struct Object *ob, struct ScrArea *sa); /* generic animation channels */ void ED_operatortypes_animchannels(void); -void ED_keymap_animchannels(struct wmWindowManager *wm); +void ED_keymap_animchannels(struct wmKeyConfig *keyconf); /* generic time editing */ void ED_operatortypes_anim(void); -void ED_keymap_anim(struct wmWindowManager *wm); +void ED_keymap_anim(struct wmKeyConfig *keyconf); /* ************************************************ */ diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 8bdfe41ef80..6479030bcd1 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -35,7 +35,7 @@ struct Bone; struct bArmature; struct bPoseChannel; struct wmOperator; -struct wmWindowManager; +struct wmKeyConfig; struct ListBase; struct View3D; struct ViewContext; @@ -92,7 +92,7 @@ typedef struct EditBone /* armature_ops.c */ void ED_operatortypes_armature(void); -void ED_keymap_armature(struct wmWindowManager *wm); +void ED_keymap_armature(struct wmKeyConfig *keyconf); /* editarmature.c */ void ED_armature_from_edit(struct Object *obedit); diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 4149c6a9cca..fea684971b2 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -36,11 +36,11 @@ struct Scene; struct Text; struct View3D; struct wmOperator; -struct wmWindowManager; +struct wmKeyConfig; /* curve_ops.c */ void ED_operatortypes_curve(void); -void ED_keymap_curve (struct wmWindowManager *wm); +void ED_keymap_curve (struct wmKeyConfig *keyconf); /* editcurve.c */ void undo_push_curve (struct bContext *C, char *name); diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 388da9a2acc..ff95f8ce6eb 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -41,7 +41,7 @@ struct bGPDframe; struct PointerRNA; struct Panel; struct ImBuf; -struct wmWindowManager; +struct wmKeyConfig; /* ------------- Grease-Pencil Helpers ---------------- */ @@ -62,7 +62,7 @@ struct bGPdata *gpencil_data_get_active(struct bContext *C); /* ----------- Grease Pencil Operators ----------------- */ -void ED_keymap_gpencil(struct wmWindowManager *wm); +void ED_keymap_gpencil(struct wmKeyConfig *keyconf); void ED_operatortypes_gpencil(void); /* ------------ Grease-Pencil Drawing API ------------------ */ diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h index 4b7a2954206..58ca85bb74c 100644 --- a/source/blender/editors/include/ED_markers.h +++ b/source/blender/editors/include/ED_markers.h @@ -28,7 +28,7 @@ #ifndef ED_MARKERS_H #define ED_MARKERS_H -struct wmWindowManager; +struct wmKeyConfig; struct bContext; struct TimeMarker; @@ -56,7 +56,7 @@ void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short sel); /* called in screen_ops.c:ED_operatortypes_screen() */ void ED_operatortypes_marker(void); /* called in screen_ops.c:ED_keymap_screen() */ -void ED_marker_keymap(struct wmWindowManager *wm); +void ED_marker_keymap(struct wmKeyConfig *keyconf); #endif /* ED_MARKERS_H */ diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index 49c1d856a27..6708a73e088 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -28,10 +28,10 @@ struct bContext; struct Object; -struct wmWindowManager; +struct wmKeyConfig; void ED_operatortypes_metaball(void); -void ED_keymap_metaball(struct wmWindowManager *wm); +void ED_keymap_metaball(struct wmKeyConfig *keyconf); struct MetaElem *add_metaball_primitive(struct bContext *C, int type, int newname); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index fd88f9889ae..cf0e6eb01c3 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -38,6 +38,7 @@ struct EditFace; struct bContext; struct wmOperator; struct wmWindowManager; +struct wmKeyConfig; struct ReportList; struct EditSelection; struct ViewContext; @@ -84,13 +85,13 @@ int join_mesh_exec(struct bContext *C, struct wmOperator *op); /* mesh_ops.c */ void ED_operatortypes_mesh(void); -void ED_keymap_mesh(struct wmWindowManager *wm); +void ED_keymap_mesh(struct wmKeyConfig *keyconf); /* editmesh.c */ void ED_spacetypes_init(void); -void ED_keymap_mesh(struct wmWindowManager *wm); +void ED_keymap_mesh(struct wmKeyConfig *keyconf); void make_editMesh(struct Scene *scene, struct Object *ob); void load_editMesh(struct Scene *scene, struct Object *ob); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 363795afeab..ec763fe3dfc 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -28,7 +28,7 @@ #ifndef ED_OBJECT_H #define ED_OBJECT_H -struct wmWindowManager; +struct wmKeyConfig; struct Scene; struct Object; struct bContext; @@ -44,7 +44,7 @@ struct ModifierData; /* object_edit.c */ void ED_operatortypes_object(void); -void ED_keymap_object(struct wmWindowManager *wm); +void ED_keymap_object(struct wmKeyConfig *keyconf); /* send your own notifier for select! */ void ED_base_object_select(struct Base *base, short mode); diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index a052142102d..3d7fc5ea15b 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -36,7 +36,7 @@ struct ParticleEditSettings; struct ParticleSystem; struct RadialControl; struct rcti; -struct wmWindowManager; +struct wmKeyConfig; struct PTCacheEdit; struct Scene; diff --git a/source/blender/editors/include/ED_physics.h b/source/blender/editors/include/ED_physics.h index ee340c54e7d..df303d7c9f1 100644 --- a/source/blender/editors/include/ED_physics.h +++ b/source/blender/editors/include/ED_physics.h @@ -30,9 +30,11 @@ #ifndef ED_PHYSICS_H #define ED_PHYSICS_H +struct wmKeyConfig; + /* operators */ void ED_operatortypes_physics(void); -void ED_keymap_physics(struct wmWindowManager *wm); +void ED_keymap_physics(struct wmKeyConfig *keyconf); #endif /* ED_PHYSICS_H */ diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 63b6a067389..18c86306e44 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -37,6 +37,7 @@ struct wmWindowManager; struct wmWindow; struct wmNotifier; struct wmEvent; +struct wmKeyConfig; struct bContext; struct SpaceType; struct Scene; @@ -63,7 +64,7 @@ void region_scissor_winrct(struct ARegion *ar, struct rcti *winrct); /* spaces */ void ED_spacetypes_init(void); -void ED_spacetypes_keymap(struct wmWindowManager *wm); +void ED_spacetypes_keymap(struct wmKeyConfig *keyconf); int ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *block, int yco); int ED_area_header_standardbuttons(const struct bContext *C, struct uiBlock *block, int yco); void ED_area_overdraw(struct bContext *C); @@ -107,7 +108,7 @@ void ED_screen_new_window(struct bContext *C, struct rcti *position, int type); void ED_update_for_newframe(const struct bContext *C, int mute); void ED_operatortypes_screen(void); -void ED_keymap_screen(struct wmWindowManager *wm); +void ED_keymap_screen(struct wmKeyConfig *keyconf); /* operators; context poll callbacks */ int ED_operator_screenactive(struct bContext *C); diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index a08f0576f42..764efb4ef0c 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -29,14 +29,14 @@ #define ED_SCULPT_H struct bContext; -struct wmWindowManager; +struct wmKeyConfig; /* sculpt.c */ void ED_operatortypes_sculpt(void); /* paint_ops.c */ void ED_operatortypes_paint(void); -void ED_keymap_paint(struct wmWindowManager *wm); +void ED_keymap_paint(struct wmKeyConfig *keyconf); /* paint_image.c */ void undo_imagepaint_step(int step); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 7f08e95aceb..a7ffefba8df 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -42,8 +42,9 @@ struct uiLayout; struct EnumPropertyItem; struct wmOperatorType; struct wmKeyMap; +struct wmKeyConfig; -void transform_keymap_for_space(struct wmWindowManager *wm, struct wmKeyMap *keymap, int spaceid); +void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid); void transform_operatortypes(void); /* ******************** Macros & Prototypes *********************** */ diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index 74a9be75db6..8823437cf79 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -34,11 +34,11 @@ struct Object; struct MTFace; struct EditFace; struct Image; -struct wmWindowManager; +struct wmKeyConfig; /* uvedit_ops.c */ void ED_operatortypes_uvedit(void); -void ED_keymap_uvedit(struct wmWindowManager *wm); +void ED_keymap_uvedit(struct wmKeyConfig *keyconf); void ED_uvedit_assign_image(struct Scene *scene, struct Object *obedit, struct Image *ima, struct Image *previma); void ED_uvedit_set_tile(struct bContext *C, struct Scene *scene, struct Object *obedit, struct Image *ima, int curtile, int dotile); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 35598db9e02..3c6ed1137ae 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -147,6 +147,7 @@ typedef struct uiLayout uiLayout; #define UI_BUT_INACTIVE (1<<23) #define UI_BUT_LAST_ACTIVE (1<<24) #define UI_BUT_UNDO (1<<25) +#define UI_BUT_IMMEDIATE (1<<26) #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 @@ -572,6 +573,8 @@ void UI_exit(void); #define UI_ITEM_R_SLIDER 4 #define UI_ITEM_R_TOGGLE 8 #define UI_ITEM_R_ICON_ONLY 16 +#define UI_ITEM_R_EVENT 32 +#define UI_ITEM_R_FULL_EVENT 64 uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int size, int em, struct uiStyle *style); void uiBlockSetCurLayout(uiBlock *block, uiLayout *layout); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 38c4d82e6da..8fbff25589d 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -128,7 +128,7 @@ struct View2D; struct View2DGrid; struct View2DScrollers; -struct wmWindowManager; +struct wmKeyConfig; struct bScreen; struct ScrArea; struct ARegion; @@ -196,7 +196,7 @@ void UI_view2d_text_cache_draw(struct ARegion *ar); /* operators */ void ui_view2d_operatortypes(void); -void UI_view2d_keymap(struct wmWindowManager *wm); +void UI_view2d_keymap(struct wmKeyConfig *keyconf); #endif /* UI_VIEW2D_H */ diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 3e5cc0e6d67..fcc41e4f533 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1958,7 +1958,10 @@ void ui_check_but(uiBut *but) if (but->flag & UI_SELECT) { short *sp= (short *)but->func_arg3; - strcpy(but->drawstr, but->str); + if(but->flag & UI_BUT_IMMEDIATE) + strcpy(but->drawstr, but->str); + else + strcpy(but->drawstr, ""); if(*sp) { char *str= but->drawstr; @@ -1974,10 +1977,10 @@ void ui_check_but(uiBut *but) } else strcat(but->drawstr, "Press a key "); - } else { - /* XXX todo, button currently only used temporarily */ - strcpy(but->drawstr, WM_key_event_string((short) ui_get_but_val(but))); } + else + strcpy(but->drawstr, but->str); + break; case BUT_TOGDUAL: diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 8dea3fa1fc3..195129eac8f 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1858,6 +1858,7 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data if(data->state == BUTTON_STATE_HIGHLIGHT) { if(ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val==KM_PRESS) { but->drawstr[0]= 0; + *(short *)but->func_arg3= 0; button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); return WM_UI_HANDLER_BREAK; } @@ -1868,9 +1869,12 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data if(event->type == MOUSEMOVE) return WM_UI_HANDLER_CONTINUE; - if(ELEM(event->type, ESCKEY, LEFTMOUSE)) { + if(event->type == ESCKEY) { /* data->cancel doesnt work, this button opens immediate */ - ui_set_but_val(but, 0); + if(but->flag & UI_BUT_IMMEDIATE) + ui_set_but_val(but, 0); + else + data->cancel= 1; button_activate_state(C, but, BUTTON_STATE_EXIT); return WM_UI_HANDLER_BREAK; } @@ -3325,6 +3329,7 @@ static uiBlock *menu_change_hotkey(bContext *C, ARegion *ar, void *arg_but) strcat(buf, " |"); but= uiDefHotKeyevtButS(block, 0, buf, 0, 0, 200, 20, dummy, dummy+1, ""); + uiButSetFlag(but, UI_BUT_IMMEDIATE); uiButSetFunc(but, do_menu_change_hotkey, arg_but, dummy); uiPopupBoundsBlock(block, 6.0f, 50, -10); @@ -3782,8 +3787,11 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA button_activate_state(C, but, BUTTON_STATE_HIGHLIGHT); /* activate right away */ - if(but->type==HOTKEYEVT) - button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); + if(but->flag & UI_BUT_IMMEDIATE) { + if(but->type==HOTKEYEVT) + button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT); + /* .. more to be added here */ + } if(type == BUTTON_ACTIVATE_OPEN) { button_activate_state(C, but, BUTTON_STATE_MENU_OPEN); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b15be940eef..eb81044852a 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -476,8 +476,20 @@ static void ui_item_enum_row(uiLayout *layout, uiBlock *block, PointerRNA *ptr, MEM_freeN(item); } +/* callback for keymap item change button */ +static void ui_keymap_but_cb(bContext *C, void *but_v, void *key_v) +{ + uiBut *but= but_v; + short modifier= *((short*)key_v); + + RNA_boolean_set(&but->rnapoin, "shift", (modifier & KM_SHIFT) != 0); + RNA_boolean_set(&but->rnapoin, "ctrl", (modifier & KM_CTRL) != 0); + RNA_boolean_set(&but->rnapoin, "alt", (modifier & KM_ALT) != 0); + RNA_boolean_set(&but->rnapoin, "oskey", (modifier & KM_OSKEY) != 0); +} + /* create label + button for RNA property */ -static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int icon_only) +static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, int icon, PointerRNA *ptr, PropertyRNA *prop, int index, int x, int y, int w, int h, int flag) { uiLayout *sub; uiBut *but=NULL; @@ -507,10 +519,26 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, char *name, i /* BUTTONS_OT_file_browse calls uiFileBrowseContextProperty */ but= uiDefIconButO(block, BUT, "BUTTONS_OT_file_browse", WM_OP_INVOKE_DEFAULT, ICON_FILESEL, x, y, UI_UNIT_X, h, "Browse for file or directory."); } - else if(subtype == PROP_DIRECTION) - uiDefButR(block, BUT_NORMAL, 0, name, 0, 0, 100, 100, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL); + else if(subtype == PROP_DIRECTION) { + uiDefButR(block, BUT_NORMAL, 0, name, x, y, 100, 100, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL); + } + else if(flag & UI_ITEM_R_EVENT) { + uiDefButR(block, KEYEVT, 0, name, x, y, w, h, ptr, RNA_property_identifier(prop), index, 0, 0, -1, -1, NULL); + } + else if(flag & UI_ITEM_R_FULL_EVENT) { + if(RNA_struct_is_a(ptr->type, &RNA_KeyMapItem)) { + static short dummy = 0; + char buf[128]; + + WM_keymap_item_to_string(ptr->data, buf, sizeof(buf)); + + but= uiDefButR(block, HOTKEYEVT, 0, buf, x, y, w, h, ptr, RNA_property_identifier(prop), 0, 0, 0, -1, -1, NULL); + but->func_arg3= &dummy; // XXX abuse + uiButSetFunc(but, ui_keymap_but_cb, but, &dummy); + } + } else - but= uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !icon_only)? NULL: "", icon, x, y, w, h); + but= uiDefAutoButR(block, ptr, prop, index, (type == PROP_ENUM && !(flag & UI_ITEM_R_ICON_ONLY))? NULL: "", icon, x, y, w, h); uiBlockSetCurLayout(block, layout); return but; @@ -897,7 +925,7 @@ void uiItemFullR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, Proper ui_item_enum_row(layout, block, ptr, prop, name, 0, 0, w, h, icon_only); /* property with separate label */ else if(type == PROP_ENUM || type == PROP_STRING || type == PROP_POINTER) { - but= ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, icon_only); + but= ui_item_with_label(layout, block, name, icon, ptr, prop, index, 0, 0, w, h, flag); ui_but_add_search(but, ptr, prop, NULL, NULL); } /* single button */ diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 1d56ed4fb6a..eca4eef230c 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -126,10 +126,12 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind void uiDefAutoButsRNA(const bContext *C, uiLayout *layout, PointerRNA *ptr, int columns) { uiLayout *split, *col; + int flag; char *name; RNA_STRUCT_BEGIN(ptr, prop) { - if(strcmp(RNA_property_identifier(prop), "rna_type") == 0) + flag= RNA_property_flag(prop); + if(flag & PROP_HIDDEN) continue; name= (char*)RNA_property_ui_name(prop); diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 0af5a5cac97..ef37f6e530a 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -1407,9 +1407,9 @@ void ui_view2d_operatortypes(void) WM_operatortype_append(VIEW2D_OT_reset); } -void UI_view2d_keymap(wmWindowManager *wm) +void UI_view2d_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "View2D", 0, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "View2D", 0, 0); /* pan/scroll */ WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); @@ -1445,7 +1445,7 @@ void UI_view2d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW2D_OT_scroller_activate", LEFTMOUSE, KM_PRESS, 0, 0); /* Alternative keymap for buttons listview */ - keymap= WM_keymap_find(wm, "View2D Buttons List", 0, 0); + keymap= WM_keymap_find(keyconf, "View2D Buttons List", 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_pan", MIDDLEMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_down", WHEELDOWNMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW2D_OT_scroll_up", WHEELUPMOUSE, KM_PRESS, 0, 0); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 4c9f63f910c..4669f7a6741 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -1240,36 +1240,34 @@ static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *ptr, EnumPropertyItem *item= NULL; int totitem= 0; - if(C==NULL) { - /* needed for doc generation */ - RNA_enum_items_add(&item, &totitem, prop_simvertex_types); - RNA_enum_items_add(&item, &totitem, prop_simedge_types); - RNA_enum_items_add(&item, &totitem, prop_simface_types); - RNA_enum_item_end(&item, &totitem); - *free= 1; + if(C) { + obedit= CTX_data_edit_object(C); - return item; + if(obedit && obedit->type == OB_MESH) { + EditMesh *em= BKE_mesh_get_editmesh(obedit->data); + + if(em->selectmode & SCE_SELECT_VERTEX) + RNA_enum_items_add(&item, &totitem, prop_simvertex_types); + else if(em->selectmode & SCE_SELECT_EDGE) + RNA_enum_items_add(&item, &totitem, prop_simedge_types); + else if(em->selectmode & SCE_SELECT_FACE) + RNA_enum_items_add(&item, &totitem, prop_simface_types); + RNA_enum_item_end(&item, &totitem); + + *free= 1; + + return item; + } } - - obedit= CTX_data_edit_object(C); - - if(obedit && obedit->type == OB_MESH) { - EditMesh *em= BKE_mesh_get_editmesh(obedit->data); - if(em->selectmode & SCE_SELECT_VERTEX) - RNA_enum_items_add(&item, &totitem, prop_simvertex_types); - else if(em->selectmode & SCE_SELECT_EDGE) - RNA_enum_items_add(&item, &totitem, prop_simedge_types); - else if(em->selectmode & SCE_SELECT_FACE) - RNA_enum_items_add(&item, &totitem, prop_simface_types); - RNA_enum_item_end(&item, &totitem); - - *free= 1; - - return item; - } + /* needed for doc generation */ + RNA_enum_items_add(&item, &totitem, prop_simvertex_types); + RNA_enum_items_add(&item, &totitem, prop_simedge_types); + RNA_enum_items_add(&item, &totitem, prop_simface_types); + RNA_enum_item_end(&item, &totitem); + *free= 1; - return NULL; + return item; } void MESH_OT_select_similar(wmOperatorType *ot) @@ -1290,7 +1288,7 @@ void MESH_OT_select_similar(wmOperatorType *ot) ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; /* properties */ - prop= RNA_def_enum(ot->srna, "type", prop_simvertex_types, 0, "Type", ""); + prop= RNA_def_enum(ot->srna, "type", prop_simvertex_types, SIMVERT_NORMAL, "Type", ""); RNA_def_enum_funcs(prop, select_similar_type_itemf); } diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 13d73faeb98..6f94db38316 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -348,12 +348,12 @@ void ED_operatortypes_mesh(void) } /* note mesh keymap also for other space? */ -void ED_keymap_mesh(wmWindowManager *wm) +void ED_keymap_mesh(wmKeyConfig *keyconf) { wmKeyMap *keymap; - wmKeymapItem *kmi; + wmKeyMapItem *kmi; - keymap= WM_keymap_find(wm, "EditMesh", 0, 0); + keymap= WM_keymap_find(keyconf, "EditMesh", 0, 0); keymap->poll= ED_operator_editmesh; WM_keymap_add_item(keymap, "MESH_OT_loopcut", RKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c index dd8a18f385c..01da90212a0 100644 --- a/source/blender/editors/metaball/mball_ops.c +++ b/source/blender/editors/metaball/mball_ops.c @@ -51,11 +51,11 @@ void ED_operatortypes_metaball(void) WM_operatortype_append(MBALL_OT_select_random_metaelems); } -void ED_keymap_metaball(wmWindowManager *wm) +void ED_keymap_metaball(wmKeyConfig *keyconf) { wmKeyMap *keymap; - keymap= WM_keymap_find(wm, "Metaball", 0, 0); + keymap= WM_keymap_find(keyconf, "Metaball", 0, 0); keymap->poll= ED_operator_editmball; WM_keymap_add_item(keymap, "OBJECT_OT_metaball_add", AKEY, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 82135bf3804..f2f24c099bc 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -196,12 +196,12 @@ static int object_mode_poll(bContext *C) return (!ob || ob->mode == OB_MODE_OBJECT); } -void ED_keymap_object(wmWindowManager *wm) +void ED_keymap_object(wmKeyConfig *keyconf) { wmKeyMap *keymap; - wmKeymapItem *kmi; + wmKeyMapItem *kmi; - keymap= WM_keymap_find(wm, "Object Non-modal", 0, 0); + keymap= WM_keymap_find(keyconf, "Object Non-modal", 0, 0); /* Note: this keymap works disregarding mode */ WM_keymap_add_item(keymap, "OBJECT_OT_editmode_toggle", TABKEY, KM_PRESS, 0, 0); @@ -217,7 +217,7 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_add_item(keymap, "OBJECT_OT_center_set", CKEY, KM_PRESS, KM_ALT|KM_SHIFT|KM_CTRL, 0); /* Note: this keymap gets disabled in non-objectmode, */ - keymap= WM_keymap_find(wm, "Object Mode", 0, 0); + keymap= WM_keymap_find(keyconf, "Object Mode", 0, 0); keymap->poll= object_mode_poll; WM_keymap_add_item(keymap, "OBJECT_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); @@ -264,7 +264,7 @@ void ED_keymap_object(wmWindowManager *wm) WM_keymap_verify_item(keymap, "GROUP_OT_objects_remove_active", GKEY, KM_PRESS, KM_SHIFT|KM_ALT, 0); /* Lattice */ - keymap= WM_keymap_find(wm, "Lattice", 0, 0); + keymap= WM_keymap_find(keyconf, "Lattice", 0, 0); keymap->poll= ED_operator_editlattice; WM_keymap_add_item(keymap, "LATTICE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index ddc5fb9c9b6..0ebbfa6b701 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -83,11 +83,11 @@ static void operatortypes_particle(void) WM_operatortype_append(PARTICLE_OT_dupliob_move_down); } -static void keymap_particle(wmWindowManager *wm) +static void keymap_particle(wmKeyConfig *keyconf) { wmKeyMap *keymap; - keymap= WM_keymap_find(wm, "Particle", 0, 0); + keymap= WM_keymap_find(keyconf, "Particle", 0, 0); keymap->poll= PE_poll; WM_keymap_add_item(keymap, "PARTICLE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); @@ -166,10 +166,10 @@ void ED_operatortypes_physics(void) operatortypes_pointcache(); } -void ED_keymap_physics(wmWindowManager *wm) +void ED_keymap_physics(wmKeyConfig *keyconf) { - keymap_particle(wm); - //keymap_pointcache(wm); + keymap_particle(keyconf); + //keymap_pointcache(keyconf); } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index fb782837d5e..f539020c93d 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -824,24 +824,24 @@ static void ed_default_handlers(wmWindowManager *wm, ListBase *handlers, int fla UI_add_region_handlers(handlers); } if(flag & ED_KEYMAP_VIEW2D) { - wmKeyMap *keymap= WM_keymap_find(wm, "View2D", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "View2D", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if(flag & ED_KEYMAP_MARKERS) { - wmKeyMap *keymap= WM_keymap_find(wm, "Markers", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Markers", 0, 0); WM_event_add_keymap_handler(handlers, keymap); // XXX need boundbox check urgently!!! } if(flag & ED_KEYMAP_ANIMATION) { - wmKeyMap *keymap= WM_keymap_find(wm, "Animation", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Animation", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if(flag & ED_KEYMAP_FRAMES) { - wmKeyMap *keymap= WM_keymap_find(wm, "Frames", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Frames", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } if(flag & ED_KEYMAP_GPENCIL) { - wmKeyMap *keymap= WM_keymap_find(wm, "Grease Pencil", 0, 0); + wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0); WM_event_add_keymap_handler(handlers, keymap); } } @@ -1371,7 +1371,7 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy); - keymap= WM_keymap_find(wm, "View2D Buttons List", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "View2D Buttons List", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 8d8c2eba2a8..7ba83753fee 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2550,7 +2550,7 @@ static ScrArea *find_empty_image_area(bContext *C) static void screen_set_image_output(bContext *C, int mx, int my) { Scene *scene= CTX_data_scene(C); - ScrArea *sa; + ScrArea *sa= NULL; SpaceImage *sima; if(scene->r.displaymode==R_OUTPUT_WINDOW) { @@ -2580,8 +2580,8 @@ static void screen_set_image_output(bContext *C, int mx, int my) ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE); sa= CTX_wm_area(C); } - else { + if(!sa) { sa= find_area_showing_r_result(C); if(sa==NULL) sa= find_area_image_empty(C); @@ -3286,7 +3286,7 @@ void ED_operatortypes_screen(void) } -static void keymap_modal_set(wmWindowManager *wm) +static void keymap_modal_set(wmKeyConfig *keyconf) { static EnumPropertyItem modal_items[] = { {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, @@ -3297,7 +3297,7 @@ static void keymap_modal_set(wmWindowManager *wm) wmKeyMap *keymap; /* Standard Modal keymap ------------------------------------------------ */ - keymap= WM_modalkeymap_add(wm, "Standard Modal Map", modal_items); + keymap= WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items); WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL); WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY); @@ -3312,12 +3312,12 @@ static void keymap_modal_set(wmWindowManager *wm) } /* called in spacetypes.c */ -void ED_keymap_screen(wmWindowManager *wm) +void ED_keymap_screen(wmKeyConfig *keyconf) { wmKeyMap *keymap; /* Screen Editing ------------------------------------------------ */ - keymap= WM_keymap_find(wm, "Screen Editing", 0, 0); + keymap= WM_keymap_find(keyconf, "Screen Editing", 0, 0); RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0); RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1); @@ -3334,7 +3334,7 @@ void ED_keymap_screen(wmWindowManager *wm) /* Screen General ------------------------------------------------ */ - keymap= WM_keymap_find(wm, "Screen", 0, 0); + keymap= WM_keymap_find(keyconf, "Screen", 0, 0); /* standard timers */ WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0); @@ -3389,7 +3389,7 @@ void ED_keymap_screen(wmWindowManager *wm) /* Anim Playback ------------------------------------------------ */ - keymap= WM_keymap_find(wm, "Frames", 0, 0); + keymap= WM_keymap_find(keyconf, "Frames", 0, 0); /* frame offsets */ RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10); @@ -3409,6 +3409,6 @@ void ED_keymap_screen(wmWindowManager *wm) WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", KKEY, KM_PRESS, 0, LKEY); RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1); - keymap_modal_set(wm); + keymap_modal_set(keyconf); } diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 514c80d929d..11dbeffdb22 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -134,12 +134,12 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_color_set); } -void ED_keymap_paint(wmWindowManager *wm) +void ED_keymap_paint(wmKeyConfig *keyconf) { wmKeyMap *keymap; /* Sculpt mode */ - keymap= WM_keymap_find(wm, "Sculpt", 0, 0); + keymap= WM_keymap_find(keyconf, "Sculpt", 0, 0); keymap->poll= sculpt_poll; RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); @@ -150,7 +150,7 @@ void ED_keymap_paint(wmWindowManager *wm) WM_keymap_add_item(keymap, "SCULPT_OT_brush_stroke", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); /* Vertex Paint mode */ - keymap= WM_keymap_find(wm, "Vertex Paint", 0, 0); + keymap= WM_keymap_find(keyconf, "Vertex Paint", 0, 0); keymap->poll= vertex_paint_poll; RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_vertex_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); @@ -159,7 +159,7 @@ void ED_keymap_paint(wmWindowManager *wm) WM_keymap_add_item(keymap, "PAINT_OT_sample_color", RIGHTMOUSE, KM_PRESS, 0, 0); /* Weight Paint mode */ - keymap= WM_keymap_find(wm, "Weight Paint", 0, 0); + keymap= WM_keymap_find(keyconf, "Weight Paint", 0, 0); keymap->poll= weight_paint_poll; RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_weight_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); @@ -168,7 +168,7 @@ void ED_keymap_paint(wmWindowManager *wm) WM_keymap_verify_item(keymap, "PAINT_OT_weight_paint", LEFTMOUSE, KM_PRESS, 0, 0); /* Image/Texture Paint mode */ - keymap= WM_keymap_find(wm, "Image Paint", 0, 0); + keymap= WM_keymap_find(keyconf, "Image Paint", 0, 0); keymap->poll= image_texture_paint_poll; RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_texture_paint_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE); diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 4326bed62d3..c436475b537 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -124,7 +124,7 @@ enum { /* ***************************************** */ /* action_ops.c */ void action_operatortypes(void); -void action_keymap(struct wmWindowManager *wm); +void action_keymap(struct wmKeyConfig *keyconf); #endif /* ED_ACTION_INTERN_H */ diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index 00b22232608..ba504fa8a69 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -91,9 +91,9 @@ void action_operatortypes(void) /* ************************** registration - keymaps **********************************/ -static void action_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) +static void action_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) { - wmKeymapItem *kmi; + wmKeyMapItem *kmi; /* action_select.c - selection tools */ /* click-select */ @@ -156,7 +156,7 @@ static void action_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) WM_keymap_add_item(keymap, "ACT_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); /* transform system */ - transform_keymap_for_space(wm, keymap, SPACE_ACTION); + transform_keymap_for_space(keyconf, keymap, SPACE_ACTION); /* test */ /* WM_keymap_add_item(keymap, "ACT_OT_test", QKEY, KM_PRESS, 0, 0); */ @@ -164,7 +164,7 @@ static void action_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) /* --------------- */ -void action_keymap(wmWindowManager *wm) +void action_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; @@ -175,7 +175,7 @@ void action_keymap(wmWindowManager *wm) */ /* keyframes */ - keymap= WM_keymap_find(wm, "Action_Keys", SPACE_ACTION, 0); - action_keymap_keyframes(wm, keymap); + keymap= WM_keymap_find(keyconf, "Action_Keys", SPACE_ACTION, 0); + action_keymap_keyframes(keyconf, keymap); } diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 3b275cab814..07de15a26b4 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -158,7 +158,7 @@ static void action_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Action_Keys", SPACE_ACTION, 0); + keymap= WM_keymap_find(wm->defaultconf, "Action_Keys", SPACE_ACTION, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -221,7 +221,7 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Animation_Channels", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Animation_Channels", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 8c563c98d9b..397da005543 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -110,35 +110,35 @@ void ED_spacetypes_init(void) /* called in wm.c */ /* keymap definitions are registered only once per WM initialize, usually on file read, using the keymap the actual areas/regions add the handlers */ -void ED_spacetypes_keymap(wmWindowManager *wm) +void ED_spacetypes_keymap(wmKeyConfig *keyconf) { const ListBase *spacetypes; SpaceType *stype; ARegionType *atype; - ED_keymap_screen(wm); - ED_keymap_anim(wm); - ED_keymap_animchannels(wm); - ED_keymap_gpencil(wm); - ED_keymap_object(wm); - ED_keymap_mesh(wm); - ED_keymap_uvedit(wm); - ED_keymap_curve(wm); - ED_keymap_armature(wm); - ED_keymap_physics(wm); - ED_keymap_metaball(wm); - ED_keymap_paint(wm); - ED_marker_keymap(wm); + ED_keymap_screen(keyconf); + ED_keymap_anim(keyconf); + ED_keymap_animchannels(keyconf); + ED_keymap_gpencil(keyconf); + ED_keymap_object(keyconf); + ED_keymap_mesh(keyconf); + ED_keymap_uvedit(keyconf); + ED_keymap_curve(keyconf); + ED_keymap_armature(keyconf); + ED_keymap_physics(keyconf); + ED_keymap_metaball(keyconf); + ED_keymap_paint(keyconf); + ED_marker_keymap(keyconf); - UI_view2d_keymap(wm); + UI_view2d_keymap(keyconf); spacetypes = BKE_spacetypes_list(); for(stype=spacetypes->first; stype; stype=stype->next) { if(stype->keymap) - stype->keymap(wm); + stype->keymap(keyconf); for(atype=stype->regiontypes.first; atype; atype=atype->next) { if(atype->keymap) - atype->keymap(wm); + atype->keymap(keyconf); } } } @@ -234,7 +234,7 @@ static void xxx_operatortypes(void) /* register operator types for this space */ } -static void xxx_keymap(wmWindowManager *wm) +static void xxx_keymap(wmKeyConfig *keyconf) { /* add default items to keymap */ } diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 6ffbb79f273..03d126a3e7b 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -142,7 +142,7 @@ static void buttons_main_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "Buttons Generic", SPACE_BUTS, 0); + keymap= WM_keymap_find(wm->defaultconf, "Buttons Generic", SPACE_BUTS, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -189,9 +189,9 @@ void buttons_operatortypes(void) WM_operatortype_append(BUTTONS_OT_file_browse); } -void buttons_keymap(struct wmWindowManager *wm) +void buttons_keymap(struct wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Buttons Generic", SPACE_BUTS, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Buttons Generic", SPACE_BUTS, 0); WM_keymap_add_item(keymap, "BUTTONS_OT_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0); } diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 19fb575ed16..49bc3adb5b9 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -152,7 +152,7 @@ static void console_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Console", SPACE_CONSOLE, 0); + keymap= WM_keymap_find(wm->defaultconf, "Console", SPACE_CONSOLE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -232,9 +232,9 @@ void console_operatortypes(void) WM_operatortype_append(CONSOLE_OT_report_copy); } -void console_keymap(struct wmWindowManager *wm) +void console_keymap(struct wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Console", SPACE_CONSOLE, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Console", SPACE_CONSOLE, 0); #ifdef __APPLE__ RNA_enum_set(WM_keymap_add_item(keymap, "CONSOLE_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN); diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index 1b54277c383..afdb0d24917 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -172,16 +172,16 @@ static void file_panel_operator(const bContext *C, Panel *pa) { SpaceFile *sfile= CTX_wm_space_file(C); wmOperator *op= sfile->op; - int empty= 1; + int empty= 1, flag; if(op->type->ui) { op->type->ui((bContext*)C, op->ptr, pa->layout); } else { RNA_STRUCT_BEGIN(op->ptr, prop) { - if(strcmp(RNA_property_identifier(prop), "rna_type") == 0) - continue; - if(strcmp(RNA_property_identifier(prop), "filemode") == 0) + flag= RNA_property_flag(prop); + + if(flag & PROP_HIDDEN) continue; if(strcmp(RNA_property_identifier(prop), "path") == 0) continue; @@ -189,10 +189,6 @@ static void file_panel_operator(const bContext *C, Panel *pa) continue; if(strcmp(RNA_property_identifier(prop), "filename") == 0) continue; - if(strcmp(RNA_property_identifier(prop), "display") == 0) - continue; - if(strncmp(RNA_property_identifier(prop), "filter", 6) == 0) - continue; uiItemFullR(pa->layout, NULL, 0, op->ptr, prop, -1, 0, 0); empty= 0; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 8257aa5482f..94d90929d80 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -406,7 +406,7 @@ void folderlist_pushdir(ListBase* folderlist, const char *dir) previous_folder = folderlist->last; // check if already exists - if(previous_folder){ + if(previous_folder && previous_folder->foldername){ if(! strcmp(previous_folder->foldername, dir)){ return; } diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 1f461f1bbd5..9f5d889c7b9 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -124,7 +124,10 @@ short ED_fileselect_set_params(SpaceFile *sfile) if (op) { BLI_strncpy(params->title, op->type->name, sizeof(params->title)); - params->type = RNA_int_get(op->ptr, "filemode"); + if(RNA_struct_find_property(op->ptr, "filename")) + params->type = RNA_int_get(op->ptr, "filemode"); + else + params->type = FILE_SPECIAL; if (RNA_property_is_set(op->ptr, "path")) { RNA_string_get(op->ptr, "path", name); @@ -140,15 +143,24 @@ short ED_fileselect_set_params(SpaceFile *sfile) } } params->filter = 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_blender") ? BLENDERFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_image") ? IMAGEFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_movie") ? MOVIEFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_python") ? PYSCRIPTFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_font") ? FTFONTFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_sound") ? SOUNDFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0; - params->filter |= RNA_boolean_get(op->ptr, "filter_folder") ? FOLDERFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_blender")) + params->filter |= RNA_boolean_get(op->ptr, "filter_blender") ? BLENDERFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_image")) + params->filter |= RNA_boolean_get(op->ptr, "filter_image") ? IMAGEFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_movie")) + params->filter |= RNA_boolean_get(op->ptr, "filter_movie") ? MOVIEFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_text")) + params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_python")) + params->filter |= RNA_boolean_get(op->ptr, "filter_python") ? PYSCRIPTFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_font")) + params->filter |= RNA_boolean_get(op->ptr, "filter_font") ? FTFONTFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_sound")) + params->filter |= RNA_boolean_get(op->ptr, "filter_sound") ? SOUNDFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_text")) + params->filter |= RNA_boolean_get(op->ptr, "filter_text") ? TEXTFILE : 0; + if(RNA_struct_find_property(op->ptr, "filter_folder")) + params->filter |= RNA_boolean_get(op->ptr, "filter_folder") ? FOLDERFILE : 0; if (params->filter != 0) params->flag |= FILE_FILTER; diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 77f50d91e77..4d3376e0e1f 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -253,10 +253,10 @@ static void file_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymaps */ - keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); + keymap= WM_keymap_find(wm->defaultconf, "File", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "FileMain", SPACE_FILE, 0); + keymap= WM_keymap_find(wm->defaultconf, "FileMain", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); @@ -364,11 +364,11 @@ void file_operatortypes(void) } /* NOTE: do not add .blend file reading on this level */ -void file_keymap(struct wmWindowManager *wm) +void file_keymap(struct wmKeyConfig *keyconf) { - wmKeymapItem *kmi; + wmKeyMapItem *kmi; /* keys for all areas */ - wmKeyMap *keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "File", SPACE_FILE, 0); WM_keymap_add_item(keymap, "FILE_OT_bookmark_toggle", NKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_parent", PKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_add_bookmark", BKEY, KM_PRESS, KM_CTRL, 0); @@ -380,7 +380,7 @@ void file_keymap(struct wmWindowManager *wm) WM_keymap_add_item(keymap, "FILE_OT_delete", DELKEY, KM_PRESS, 0, 0); /* keys for main area */ - keymap= WM_keymap_find(wm, "FileMain", SPACE_FILE, 0); + keymap= WM_keymap_find(keyconf, "FileMain", SPACE_FILE, 0); WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "FILE_OT_select_border", BKEY, KM_PRESS, 0, 0); @@ -401,7 +401,7 @@ void file_keymap(struct wmWindowManager *wm) RNA_int_set(kmi->ptr, "increment",-100); /* keys for button area (top) */ - keymap= WM_keymap_find(wm, "FileButtons", SPACE_FILE, 0); + keymap= WM_keymap_find(keyconf, "FileButtons", SPACE_FILE, 0); WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0); kmi = WM_keymap_add_item(keymap, "FILE_OT_filenum", PADPLUSKEY, KM_PRESS, 0, 0); RNA_int_set(kmi->ptr, "increment", 1); @@ -425,7 +425,7 @@ static void file_channel_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); /* own keymaps */ - keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); + keymap= WM_keymap_find(wm->defaultconf, "File", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -461,10 +461,10 @@ static void file_ui_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "File", SPACE_FILE, 0); + keymap= WM_keymap_find(wm->defaultconf, "File", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "FileButtons", SPACE_FILE, 0); + keymap= WM_keymap_find(wm->defaultconf, "FileButtons", SPACE_FILE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 83a565e485f..9b7c2eb3656 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -159,7 +159,7 @@ int graphop_selected_fcurve_poll(struct bContext *C); /* ***************************************** */ /* graph_ops.c */ -void graphedit_keymap(struct wmWindowManager *wm); +void graphedit_keymap(struct wmKeyConfig *keyconf); void graphedit_operatortypes(void); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index b82055064f8..ab35bda0e2f 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -141,9 +141,9 @@ void graphedit_operatortypes(void) /* ************************** registration - keymaps **********************************/ -static void graphedit_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) +static void graphedit_keymap_keyframes (wmKeyConfig *keyconf, wmKeyMap *keymap) { - wmKeymapItem *kmi; + wmKeyMapItem *kmi; /* view */ WM_keymap_add_item(keymap, "GRAPH_OT_handles_view_toggle", HKEY, KM_PRESS, KM_CTRL, 0); @@ -225,17 +225,17 @@ static void graphedit_keymap_keyframes (wmWindowManager *wm, wmKeyMap *keymap) /* transform system */ - transform_keymap_for_space(wm, keymap, SPACE_IPO); + transform_keymap_for_space(keyconf, keymap, SPACE_IPO); } /* --------------- */ -void graphedit_keymap(wmWindowManager *wm) +void graphedit_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; /* keymap for all regions */ - keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(keyconf, "GraphEdit Generic", SPACE_IPO, 0); WM_keymap_add_item(keymap, "GRAPH_OT_properties", NKEY, KM_PRESS, 0, 0); /* channels */ @@ -245,7 +245,7 @@ void graphedit_keymap(wmWindowManager *wm) */ /* keyframes */ - keymap= WM_keymap_find(wm, "GraphEdit Keys", SPACE_IPO, 0); - graphedit_keymap_keyframes(wm, keymap); + keymap= WM_keymap_find(keyconf, "GraphEdit Keys", SPACE_IPO, 0); + graphedit_keymap_keyframes(keyconf, keymap); } diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index a7ea2294ed4..c8d2c571a16 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -208,9 +208,9 @@ static void graph_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "GraphEdit Keys", SPACE_IPO, 0); + keymap= WM_keymap_find(wm->defaultconf, "GraphEdit Keys", SPACE_IPO, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm->defaultconf, "GraphEdit Generic", SPACE_IPO, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -286,9 +286,9 @@ static void graph_channel_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Animation_Channels", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Animation_Channels", 0, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm->defaultconf, "GraphEdit Generic", SPACE_IPO, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -356,7 +356,7 @@ static void graph_buttons_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "GraphEdit Generic", SPACE_IPO, 0); + keymap= WM_keymap_find(wm->defaultconf, "GraphEdit Generic", SPACE_IPO, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 4cf59c9a28e..e64bb1a4209 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -202,9 +202,9 @@ void image_operatortypes(void) WM_operatortype_append(IMAGE_OT_properties); } -void image_keymap(struct wmWindowManager *wm) +void image_keymap(struct wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Image Generic", SPACE_IMAGE, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Image Generic", SPACE_IMAGE, 0); WM_keymap_add_item(keymap, "IMAGE_OT_new", NKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "IMAGE_OT_open", OKEY, KM_PRESS, KM_ALT, 0); @@ -212,7 +212,7 @@ void image_keymap(struct wmWindowManager *wm) WM_keymap_add_item(keymap, "IMAGE_OT_save", SKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "IMAGE_OT_properties", NKEY, KM_PRESS, 0, 0); - keymap= WM_keymap_find(wm, "Image", SPACE_IMAGE, 0); + keymap= WM_keymap_find(keyconf, "Image", SPACE_IMAGE, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_all", HOMEKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "IMAGE_OT_view_selected", PADPERIOD, KM_PRESS, 0, 0); @@ -389,16 +389,16 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar) // UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* image paint polls for mode */ - keymap= WM_keymap_find(wm, "Image Paint", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm->defaultconf, "Image Paint", SPACE_IMAGE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "UVEdit", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "UVEdit", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* own keymaps */ - keymap= WM_keymap_find(wm, "Image Generic", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm->defaultconf, "Image Generic", SPACE_IMAGE, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Image", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm->defaultconf, "Image", SPACE_IMAGE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -463,7 +463,7 @@ static void image_buttons_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "Image Generic", SPACE_IMAGE, 0); + keymap= WM_keymap_find(wm->defaultconf, "Image Generic", SPACE_IMAGE, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/space_info/space_info.c b/source/blender/editors/space_info/space_info.c index d3f9c97205c..518553c9a7a 100644 --- a/source/blender/editors/space_info/space_info.c +++ b/source/blender/editors/space_info/space_info.c @@ -134,7 +134,7 @@ void info_operatortypes(void) WM_operatortype_append(FILE_OT_find_missing_files); } -void info_keymap(struct wmWindowManager *wm) +void info_keymap(struct wmKeyConfig *keyconf) { } diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 7043d625ab0..836ac4c6659 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -186,9 +186,9 @@ void logic_operatortypes(void) } -void logic_keymap(struct wmWindowManager *wm) +void logic_keymap(struct wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Logic Generic", SPACE_LOGIC, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Logic Generic", SPACE_LOGIC, 0); WM_keymap_add_item(keymap, "LOGIC_OT_properties", NKEY, KM_PRESS, 0, 0); } @@ -239,7 +239,7 @@ static void logic_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymaps */ - keymap= WM_keymap_find(wm, "Logic Generic", SPACE_LOGIC, 0); + keymap= WM_keymap_find(wm->defaultconf, "Logic Generic", SPACE_LOGIC, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -280,7 +280,7 @@ static void logic_buttons_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "Logic Generic", SPACE_LOGIC, 0); + keymap= WM_keymap_find(wm->defaultconf, "Logic Generic", SPACE_LOGIC, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/space_nla/nla_intern.h b/source/blender/editors/space_nla/nla_intern.h index e4557ec878f..91c1decc576 100644 --- a/source/blender/editors/space_nla/nla_intern.h +++ b/source/blender/editors/space_nla/nla_intern.h @@ -130,7 +130,7 @@ short nlaedit_is_tweakmode_on(bAnimContext *ac); /* --- */ void nla_operatortypes(void); -void nla_keymap(wmWindowManager *wm); +void nla_keymap(wmKeyConfig *keyconf); #endif /* ED_NLA_INTERN_H */ diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 5ea2e99ad6a..6c940f32c24 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -167,7 +167,7 @@ void nla_operatortypes(void) /* ************************** registration - keymaps **********************************/ -static void nla_keymap_channels (wmWindowManager *wm, wmKeyMap *keymap) +static void nla_keymap_channels (wmKeyConfig *keyconf, wmKeyMap *keymap) { /* NLA-specific (different to standard channels keymap) -------------------------- */ /* selection */ @@ -210,9 +210,9 @@ static void nla_keymap_channels (wmWindowManager *wm, wmKeyMap *keymap) RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 1); } -static void nla_keymap_main (wmWindowManager *wm, wmKeyMap *keymap) +static void nla_keymap_main (wmKeyConfig *keyconf, wmKeyMap *keymap) { - wmKeymapItem *kmi; + wmKeyMapItem *kmi; /* selection */ /* click select */ @@ -277,17 +277,17 @@ static void nla_keymap_main (wmWindowManager *wm, wmKeyMap *keymap) WM_keymap_add_item(keymap, "NLA_OT_fmodifier_add", MKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); /* transform system */ - transform_keymap_for_space(wm, keymap, SPACE_NLA); + transform_keymap_for_space(keyconf, keymap, SPACE_NLA); } /* --------------- */ -void nla_keymap(wmWindowManager *wm) +void nla_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; /* keymap for all regions */ - keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(keyconf, "NLA Generic", SPACE_NLA, 0); WM_keymap_add_item(keymap, "NLA_OT_properties", NKEY, KM_PRESS, 0, 0); /* channels */ @@ -297,11 +297,11 @@ void nla_keymap(wmWindowManager *wm) * * However, those operations which involve clicking on channels and/or the placement of them in the view are implemented here instead */ - keymap= WM_keymap_find(wm, "NLA Channels", SPACE_NLA, 0); - nla_keymap_channels(wm, keymap); + keymap= WM_keymap_find(keyconf, "NLA Channels", SPACE_NLA, 0); + nla_keymap_channels(keyconf, keymap); /* data */ - keymap= WM_keymap_find(wm, "NLA Data", SPACE_NLA, 0); - nla_keymap_main(wm, keymap); + keymap= WM_keymap_find(keyconf, "NLA Data", SPACE_NLA, 0); + nla_keymap_main(keyconf, keymap); } diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 41435810889..32ff7766690 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -214,9 +214,9 @@ static void nla_channel_area_init(wmWindowManager *wm, ARegion *ar) /* own keymap */ // TODO: cannot use generic copy, need special NLA version - keymap= WM_keymap_find(wm, "NLA Channels", SPACE_NLA, 0); + keymap= WM_keymap_find(wm->defaultconf, "NLA Channels", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm->defaultconf, "NLA Generic", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -259,9 +259,9 @@ static void nla_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "NLA Data", SPACE_NLA, 0); + keymap= WM_keymap_find(wm->defaultconf, "NLA Data", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); - keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm->defaultconf, "NLA Generic", SPACE_NLA, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -358,7 +358,7 @@ static void nla_buttons_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "NLA Generic", SPACE_NLA, 0); + keymap= WM_keymap_find(wm->defaultconf, "NLA Generic", SPACE_NLA, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 9f28a5e3dcb..f55ecf1d0f4 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -53,7 +53,7 @@ void drawnodespace(const bContext *C, ARegion *ar, View2D *v2d); /* node_ops.c */ void node_operatortypes(void); -void node_keymap(wmWindowManager *wm); +void node_keymap(wmKeyConfig *keyconf); /* node_select.c */ void NODE_OT_select(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index 880cc489838..443b83a91bc 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -67,10 +67,10 @@ void node_operatortypes(void) WM_operatortype_append(NODE_OT_group_edit); } -void node_keymap(struct wmWindowManager *wm) +void node_keymap(struct wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Node", SPACE_NODE, 0); - wmKeymapItem *kmi; + wmKeyMap *keymap= WM_keymap_find(keyconf, "Node", SPACE_NODE, 0); + wmKeyMapItem *kmi; /* mouse select in nodes used to be both keys, it's UI elements... */ RNA_enum_set(WM_keymap_add_item(keymap, "NODE_OT_select", ACTIONMOUSE, KM_PRESS, 0, 0)->ptr, "select_type", NODE_SELECT_MOUSE); @@ -101,5 +101,5 @@ void node_keymap(struct wmWindowManager *wm) kmi= WM_keymap_add_item(keymap, "WM_OT_call_menu", AKEY, KM_PRESS, KM_SHIFT, 0); RNA_string_set(kmi->ptr, "name", "NODE_MT_add"); - transform_keymap_for_space(wm, keymap, SPACE_NODE); + transform_keymap_for_space(keyconf, keymap, SPACE_NODE); } diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index bdd2a65984f..41140eae776 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -252,7 +252,7 @@ static void node_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Node", SPACE_NODE, 0); + keymap= WM_keymap_find(wm->defaultconf, "Node", SPACE_NODE, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c index 641137c010b..28fdc4708df 100644 --- a/source/blender/editors/space_outliner/outliner.c +++ b/source/blender/editors/space_outliner/outliner.c @@ -1113,16 +1113,16 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i } else if(type == TSE_KEYMAP) { wmKeyMap *km= (wmKeyMap *)idv; - wmKeymapItem *kmi; + wmKeyMapItem *kmi; char opname[OP_MAX_TYPENAME]; te->directdata= idv; - te->name= km->nameid; + te->name= km->idname; if(!(tselem->flag & TSE_CLOSED)) { a= 0; - for (kmi= km->keymap.first; kmi; kmi= kmi->next, a++) { + for (kmi= km->items.first; kmi; kmi= kmi->next, a++) { const char *key= WM_key_event_string(kmi->type); if(key[0]) { @@ -1408,7 +1408,7 @@ static void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) wmWindowManager *wm= mainvar->wm.first; wmKeyMap *km; - for(km= wm->keymaps.first; km; km= km->next) { + for(km= wm->defaultconf->keymaps.first; km; km= km->next) { ten= outliner_add_element(soops, &soops->tree, (void*)km, NULL, TSE_KEYMAP, 0); } } @@ -2229,14 +2229,14 @@ static int tree_element_active_sequence_dup(bContext *C, Scene *scene, TreeEleme static int tree_element_active_keymap_item(bContext *C, TreeElement *te, TreeStoreElem *tselem, int set) { - wmKeymapItem *kmi= te->directdata; + wmKeyMapItem *kmi= te->directdata; if(set==0) { - if(kmi->inactive) return 0; + if(kmi->flag & KMI_INACTIVE) return 0; return 1; } else { - kmi->inactive= !kmi->inactive; + kmi->flag ^= KMI_INACTIVE; } return 0; } @@ -4957,7 +4957,7 @@ static void outliner_draw_rnabuts(uiBlock *block, Scene *scene, ARegion *ar, Spa static void operator_call_cb(struct bContext *C, void *arg_kmi, void *arg2) { wmOperatorType *ot= arg2; - wmKeymapItem *kmi= arg_kmi; + wmKeyMapItem *kmi= arg_kmi; if(ot) BLI_strncpy(kmi->idname, ot->idname, OP_MAX_TYPENAME); @@ -4987,7 +4987,7 @@ static uiBlock *operator_search_menu(bContext *C, ARegion *ar, void *arg_kmi) static char search[OP_MAX_TYPENAME]; wmEvent event; wmWindow *win= CTX_wm_window(C); - wmKeymapItem *kmi= arg_kmi; + wmKeyMapItem *kmi= arg_kmi; wmOperatorType *ot= WM_operatortype_find(kmi->idname, 0); uiBlock *block; uiBut *but; @@ -5026,8 +5026,8 @@ static uiBlock *operator_search_menu(bContext *C, ARegion *ar, void *arg_kmi) static short keymap_menu_type(short type) { if(ISKEYBOARD(type)) return OL_KM_KEYBOARD; - if(WM_key_event_is_tweak(type)) return OL_KM_TWEAK; - if(type >= LEFTMOUSE && type <= WHEELOUTMOUSE) return OL_KM_MOUSE; + if(ISTWEAK(type)) return OL_KM_TWEAK; + if(ISMOUSE(type)) return OL_KM_MOUSE; // return OL_KM_SPECIALS; return 0; } @@ -5083,8 +5083,6 @@ static char *keymap_tweak_menu(void) str += sprintf(str, formatstr, "Left Mouse", EVT_TWEAK_L); str += sprintf(str, formatstr, "Middle Mouse", EVT_TWEAK_M); str += sprintf(str, formatstr, "Right Mouse", EVT_TWEAK_R); - str += sprintf(str, formatstr, "Button4 Mouse ", BUTTON4MOUSE); - str += sprintf(str, formatstr, "Button5 Mouse ", BUTTON5MOUSE); str += sprintf(str, formatstr, "Action Mouse", EVT_TWEAK_A); str += sprintf(str, formatstr, "Select Mouse", EVT_TWEAK_S); @@ -5115,7 +5113,7 @@ static char *keymap_tweak_dir_menu(void) static void keymap_type_cb(bContext *C, void *kmi_v, void *unused_v) { - wmKeymapItem *kmi= kmi_v; + wmKeyMapItem *kmi= kmi_v; short maptype= keymap_menu_type(kmi->type); if(maptype!=kmi->maptype) { @@ -5158,7 +5156,7 @@ static void outliner_draw_keymapbuts(uiBlock *block, ARegion *ar, SpaceOops *soo int butw3= 43; /* modifiers */ if(tselem->type == TSE_KEYMAP_ITEM) { - wmKeymapItem *kmi= te->directdata; + wmKeyMapItem *kmi= te->directdata; /* modal map? */ if(kmi->propvalue); diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 4f9a0f686b9..c71b5181d16 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -110,7 +110,7 @@ typedef struct TreeElement { /* outliner_ops.c */ void outliner_operatortypes(void); -void outliner_keymap(struct wmWindowManager *wm); +void outliner_keymap(struct wmKeyConfig *keyconf); /* outliner_header.c */ void outliner_header_buttons(const struct bContext *C, struct ARegion *ar); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index a35b91249db..3cdd054fe0e 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -74,9 +74,9 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_drivers_delete); } -void outliner_keymap(wmWindowManager *wm) +void outliner_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Outliner", SPACE_OUTLINER, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Outliner", SPACE_OUTLINER, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "extend", 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OUTLINER_OT_item_activate", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index eb0e9dafbaa..fabe889ace6 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -77,7 +77,7 @@ static void outliner_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Outliner", SPACE_OUTLINER, 0); + keymap= WM_keymap_find(wm->defaultconf, "Outliner", SPACE_OUTLINER, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_script/script_intern.h b/source/blender/editors/space_script/script_intern.h index 59858ee6289..7534fc98de1 100644 --- a/source/blender/editors/space_script/script_intern.h +++ b/source/blender/editors/space_script/script_intern.h @@ -36,7 +36,7 @@ void script_header_buttons(const bContext *C, ARegion *ar); /* script_ops.c */ void script_operatortypes(void); -void script_keymap(struct wmWindowManager *wm); +void script_keymap(struct wmKeyConfig *keyconf); /* script_edit.c */ void SCRIPT_OT_python_file_run(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_script/script_ops.c b/source/blender/editors/space_script/script_ops.c index 0e6ea9cf4fd..bf0a7e5769e 100644 --- a/source/blender/editors/space_script/script_ops.c +++ b/source/blender/editors/space_script/script_ops.c @@ -63,9 +63,9 @@ void script_operatortypes(void) WM_operatortype_append(SCRIPT_OT_python_run_ui_scripts); } -void script_keymap(wmWindowManager *wm) +void script_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Script", SPACE_SCRIPT, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Script", SPACE_SCRIPT, 0); /* TODO - this is just while we have no way to load a text datablock */ RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", PKEY, KM_PRESS, KM_CTRL|KM_SHIFT|KM_ALT, 0)->ptr, "path", "test.py"); diff --git a/source/blender/editors/space_script/space_script.c b/source/blender/editors/space_script/space_script.c index a0e73082701..eae0f77d0e1 100644 --- a/source/blender/editors/space_script/space_script.c +++ b/source/blender/editors/space_script/space_script.c @@ -138,7 +138,7 @@ static void script_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Script", SPACE_SCRIPT, 0); + keymap= WM_keymap_find(wm->defaultconf, "Script", SPACE_SCRIPT, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index ac396440a00..d45d7bf4d18 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -75,7 +75,8 @@ extern EnumPropertyItem prop_side_types[]; /* operators */ struct wmOperatorType; -struct wmWindowManager; +struct wmKeyConfig; + void SEQUENCER_OT_cut(struct wmOperatorType *ot); void SEQUENCER_OT_mute(struct wmOperatorType *ot); void SEQUENCER_OT_unmute(struct wmOperatorType *ot); @@ -137,7 +138,7 @@ enum { /* sequencer_ops.c */ void sequencer_operatortypes(void); -void sequencer_keymap(struct wmWindowManager *wm); +void sequencer_keymap(struct wmKeyConfig *keyconf); /* sequencer_scope.c */ struct ImBuf *make_waveform_view_from_ibuf(struct ImBuf * ibuf); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index 1541b32f566..eedbab779c0 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -103,10 +103,10 @@ void sequencer_operatortypes(void) } -void sequencer_keymap(wmWindowManager *wm) +void sequencer_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Sequencer", SPACE_SEQ, 0); - wmKeymapItem *kmi; + wmKeyMap *keymap= WM_keymap_find(keyconf, "Sequencer", SPACE_SEQ, 0); + wmKeyMapItem *kmi; WM_keymap_add_item(keymap, "SEQUENCER_OT_properties", NKEY, KM_PRESS, 0, 0); @@ -183,6 +183,6 @@ void sequencer_keymap(wmWindowManager *wm) WM_keymap_verify_item(keymap, "ANIM_OT_change_frame", LEFTMOUSE, KM_PRESS, 0, 0); - transform_keymap_for_space(wm, keymap, SPACE_SEQ); + transform_keymap_for_space(keyconf, keymap, SPACE_SEQ); } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index c2756b05946..626a3e6e2e0 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -190,7 +190,7 @@ static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Sequencer", SPACE_SEQ, 0); + keymap= WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_sound/space_sound.c b/source/blender/editors/space_sound/space_sound.c index 6713e19b6de..7cd9988eea0 100644 --- a/source/blender/editors/space_sound/space_sound.c +++ b/source/blender/editors/space_sound/space_sound.c @@ -147,7 +147,7 @@ static void sound_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Sound", SPACE_SOUND, 0); + keymap= WM_keymap_find(wm->defaultconf, "Sound", SPACE_SOUND, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -179,7 +179,7 @@ void sound_operatortypes(void) } -void sound_keymap(struct wmWindowManager *wm) +void sound_keymap(struct wmKeyConfig *keyconf) { } diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index e068c1a70bb..e3816ed7495 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -206,11 +206,11 @@ static void text_operatortypes(void) WM_operatortype_append(TEXT_OT_resolve_conflict); } -static void text_keymap(struct wmWindowManager *wm) +static void text_keymap(struct wmKeyConfig *keyconf) { wmKeyMap *keymap; - keymap= WM_keymap_find(wm, "Text", SPACE_TEXT, 0); + keymap= WM_keymap_find(keyconf, "Text", SPACE_TEXT, 0); #ifdef __APPLE__ RNA_enum_set(WM_keymap_add_item(keymap, "TEXT_OT_move", LEFTARROWKEY, KM_PRESS, KM_OSKEY, 0)->ptr, "type", LINE_BEGIN); @@ -336,7 +336,7 @@ static void text_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_STANDARD, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "Text", SPACE_TEXT, 0); + keymap= WM_keymap_find(wm->defaultconf, "Text", SPACE_TEXT, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 0f05eb0149d..501ac1c0cba 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -207,7 +207,7 @@ static void time_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_find(wm, "TimeLine", SPACE_TIME, 0); + keymap= WM_keymap_find(wm->defaultconf, "TimeLine", SPACE_TIME, 0); WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } diff --git a/source/blender/editors/space_time/time_intern.h b/source/blender/editors/space_time/time_intern.h index 25f4c63fed1..ac6b407d117 100644 --- a/source/blender/editors/space_time/time_intern.h +++ b/source/blender/editors/space_time/time_intern.h @@ -35,7 +35,7 @@ struct wmWindowManager; /* time_ops.c */ void time_operatortypes(void); -void time_keymap(struct wmWindowManager *wm); +void time_keymap(struct wmKeyConfig *keyconf); /* time_header.c */ void time_header_buttons(const bContext *C, ARegion *ar); diff --git a/source/blender/editors/space_time/time_ops.c b/source/blender/editors/space_time/time_ops.c index 2b073f269bf..7d91c6d0fc7 100644 --- a/source/blender/editors/space_time/time_ops.c +++ b/source/blender/editors/space_time/time_ops.c @@ -140,9 +140,9 @@ void time_operatortypes(void) WM_operatortype_append(TIME_OT_end_frame_set); } -void time_keymap(wmWindowManager *wm) +void time_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "TimeLine", SPACE_TIME, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "TimeLine", SPACE_TIME, 0); WM_keymap_add_item(keymap, "TIME_OT_start_frame_set", SKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "TIME_OT_end_frame_set", EKEY, KM_PRESS, 0, 0); diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 8c9d723ce2c..39fc2fd2bd1 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -115,7 +115,7 @@ void userpref_operatortypes(void) { } -void userpref_keymap(struct wmWindowManager *wm) +void userpref_keymap(struct wmKeyConfig *keyconf) { } @@ -167,7 +167,7 @@ void ED_spacetype_userpref(void) art->init= userpref_main_area_init; art->draw= userpref_main_area_draw; art->listener= userpref_main_area_listener; - art->keymapflag= ED_KEYMAP_UI|ED_KEYMAP_VIEW2D; + art->keymapflag= ED_KEYMAP_UI; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 735f3df9b09..e1bd48e002f 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -280,62 +280,62 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar) wmKeyMap *keymap; /* object ops. */ - keymap= WM_keymap_find(wm, "Object Non-modal", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Object Non-modal", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* pose is not modal, operator poll checks for this */ - keymap= WM_keymap_find(wm, "Pose", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Pose", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Object Mode", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Object Mode", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Image Paint", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Vertex Paint", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Vertex Paint", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Weight Paint", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Weight Paint", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Sculpt", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Sculpt", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "EditMesh", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "EditMesh", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Curve", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Curve", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Armature", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Armature", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Pose", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Pose", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Metaball", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Metaball", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Lattice", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Lattice", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* armature sketching needs to take over mouse */ - keymap= WM_keymap_find(wm, "Armature_Sketch", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Armature_Sketch", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "Particle", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Particle", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* editfont keymap swallows all... */ - keymap= WM_keymap_find(wm, "Font", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Font", 0, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); /* own keymap, last so modes can override it */ - keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm->defaultconf, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); - keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm->defaultconf, "View3D", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -491,7 +491,7 @@ static void view3d_main_area_cursor(wmWindow *win, ScrArea *sa, ARegion *ar) /* add handlers, stuff you only do once or on area/region changes */ static void view3d_header_area_init(wmWindowManager *wm, ARegion *ar) { - wmKeyMap *keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); @@ -531,7 +531,7 @@ static void view3d_buttons_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm->defaultconf, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } @@ -602,7 +602,7 @@ static void view3d_tools_area_init(wmWindowManager *wm, ARegion *ar) ED_region_panels_init(wm, ar); - keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(wm->defaultconf, "View3D Generic", SPACE_VIEW3D, 0); WM_event_add_keymap_handler(&ar->handlers, keymap); } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index c07d9108993..4c96e1fee39 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -371,7 +371,7 @@ enum { /* called in transform_ops.c, on each regeneration of keymaps */ -void viewrotate_modal_keymap(wmWindowManager *wm) +void viewrotate_modal_keymap(wmKeyConfig *keyconf) { static EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Cancel", ""}, @@ -381,12 +381,12 @@ void viewrotate_modal_keymap(wmWindowManager *wm) {0, NULL, 0, NULL, NULL}}; - wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Rotate Modal"); + wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Rotate Modal"); /* this function is called for each spacetype, only needs to add map once */ if(keymap) return; - keymap= WM_modalkeymap_add(wm, "View3D Rotate Modal", modal_items); + keymap= WM_modalkeymap_add(keyconf, "View3D Rotate Modal", modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); @@ -630,19 +630,19 @@ void VIEW3D_OT_rotate(wmOperatorType *ot) /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */ /* called in transform_ops.c, on each regeneration of keymaps */ -void viewmove_modal_keymap(wmWindowManager *wm) +void viewmove_modal_keymap(wmKeyConfig *keyconf) { static EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, {0, NULL, 0, NULL, NULL}}; - wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Move Modal"); + wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Move Modal"); /* this function is called for each spacetype, only needs to add map once */ if(keymap) return; - keymap= WM_modalkeymap_add(wm, "View3D Move Modal", modal_items); + keymap= WM_modalkeymap_add(keyconf, "View3D Move Modal", modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); @@ -749,19 +749,19 @@ void VIEW3D_OT_move(wmOperatorType *ot) /* ************************ viewzoom ******************************** */ /* called in transform_ops.c, on each regeneration of keymaps */ -void viewzoom_modal_keymap(wmWindowManager *wm) +void viewzoom_modal_keymap(wmKeyConfig *keyconf) { static EnumPropertyItem modal_items[] = { {VIEW_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, {0, NULL, 0, NULL, NULL}}; - wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Zoom Modal"); + wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Zoom Modal"); /* this function is called for each spacetype, only needs to add map once */ if(keymap) return; - keymap= WM_modalkeymap_add(wm, "View3D Zoom Modal", modal_items); + keymap= WM_modalkeymap_add(keyconf, "View3D Zoom Modal", modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, VIEW_MODAL_CONFIRM); diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index d80cec9ad48..84d1a1275a9 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -62,7 +62,7 @@ void VIEW3D_OT_layers(struct wmOperatorType *ot); /* view3d_ops.c */ void view3d_operatortypes(void); -void view3d_keymap(struct wmWindowManager *wm); +void view3d_keymap(struct wmKeyConfig *keyconf); /* view3d_edit.c */ void VIEW3D_OT_zoom(struct wmOperatorType *ot); @@ -137,10 +137,10 @@ void smooth_view(struct bContext *C, Object *, Object *, float *ofs, float *quat void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect); /* rect: for picking */ void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d); -void fly_modal_keymap(struct wmWindowManager *wm); -void viewrotate_modal_keymap(struct wmWindowManager *wm); -void viewmove_modal_keymap(struct wmWindowManager *wm); -void viewzoom_modal_keymap(struct wmWindowManager *wm); +void fly_modal_keymap(struct wmKeyConfig *keyconf); +void viewrotate_modal_keymap(struct wmKeyConfig *keyconf); +void viewmove_modal_keymap(struct wmKeyConfig *keyconf); +void viewzoom_modal_keymap(struct wmKeyConfig *keyconf); /* view3d_buttons.c */ void VIEW3D_OT_properties(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index a151ff3e73a..74074a04188 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -103,18 +103,18 @@ void view3d_operatortypes(void) transform_operatortypes(); } -void view3d_keymap(wmWindowManager *wm) +void view3d_keymap(wmKeyConfig *keyconf) { wmKeyMap *keymap; - wmKeymapItem *km; + wmKeyMapItem *km; - keymap= WM_keymap_find(wm, "View3D Generic", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(keyconf, "View3D Generic", SPACE_VIEW3D, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_properties", NKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_toolbar", TKEY, KM_PRESS, 0, 0); /* only for region 3D window */ - keymap= WM_keymap_find(wm, "View3D", SPACE_VIEW3D, 0); + keymap= WM_keymap_find(keyconf, "View3D", SPACE_VIEW3D, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, 0, 0); /* manipulator always on left mouse, not on action mouse*/ @@ -221,11 +221,11 @@ void view3d_keymap(wmWindowManager *wm) WM_keymap_add_item(keymap, "VIEW3D_OT_snap_menu", SKEY, KM_PRESS, KM_SHIFT, 0); - transform_keymap_for_space(wm, keymap, SPACE_VIEW3D); + transform_keymap_for_space(keyconf, keymap, SPACE_VIEW3D); - fly_modal_keymap(wm); - viewrotate_modal_keymap(wm); - viewmove_modal_keymap(wm); - viewzoom_modal_keymap(wm); + fly_modal_keymap(keyconf); + viewrotate_modal_keymap(keyconf); + viewmove_modal_keymap(keyconf); + viewzoom_modal_keymap(keyconf); } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 505f3abf401..d26141e3b54 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1633,7 +1633,7 @@ void VIEW3D_OT_game_start(wmOperatorType *ot) #define FLY_MODAL_PRECISION_DISABLE 16 /* called in transform_ops.c, on each regeneration of keymaps */ -void fly_modal_keymap(wmWindowManager *wm) +void fly_modal_keymap(wmKeyConfig *keyconf) { static EnumPropertyItem modal_items[] = { {FLY_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, @@ -1659,12 +1659,12 @@ void fly_modal_keymap(wmWindowManager *wm) {0, NULL, 0, NULL, NULL}}; - wmKeyMap *keymap= WM_modalkeymap_get(wm, "View3D Fly Modal"); + wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Fly Modal"); /* this function is called for each spacetype, only needs to add map once */ if(keymap) return; - keymap= WM_modalkeymap_add(wm, "View3D Fly Modal", modal_items); + keymap= WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 839c3543515..ad89d8a3a59 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -515,7 +515,7 @@ static char *transform_to_undostr(TransInfo *t) #define TFM_MODAL_SNAP_GEARS_OFF 7 /* called in transform_ops.c, on each regeneration of keymaps */ -void transform_modal_keymap(wmWindowManager *wm) +void transform_modal_keymap(wmKeyConfig *keyconf) { static EnumPropertyItem modal_items[] = { {TFM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, @@ -527,12 +527,12 @@ void transform_modal_keymap(wmWindowManager *wm) {TFM_MODAL_SNAP_GEARS_OFF, "SNAP_GEARS_OFF", 0, "Snap Off", ""}, {0, NULL, 0, NULL, NULL}}; - wmKeyMap *keymap= WM_modalkeymap_get(wm, "Transform Modal Map"); + wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Transform Modal Map"); /* this function is called for each spacetype, only needs to add map once */ if(keymap) return; - keymap= WM_modalkeymap_add(wm, "Transform Modal Map", modal_items); + keymap= WM_modalkeymap_add(keyconf, "Transform Modal Map", modal_items); /* items for modal map */ WM_modalkeymap_add_item(keymap, ESCKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CANCEL); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 1c170a31c45..60786127e3a 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -508,7 +508,7 @@ int Align(TransInfo *t, short mval[2]); void drawPropCircle(const struct bContext *C, TransInfo *t); -void transform_modal_keymap(struct wmWindowManager *wm); +void transform_modal_keymap(struct wmKeyConfig *keyconf); /*********************** transform_conversions.c ********** */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 7ef8ad17a69..0913f0ea273 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -734,12 +734,12 @@ void transform_operatortypes(void) WM_operatortype_append(TFM_OT_delete_orientation); } -void transform_keymap_for_space(struct wmWindowManager *wm, struct wmKeyMap *keymap, int spaceid) +void transform_keymap_for_space(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap, int spaceid) { - wmKeymapItem *km; + wmKeyMapItem *km; /* transform.c, only adds modal map once, checks if it's there */ - transform_modal_keymap(wm); + transform_modal_keymap(keyconf); switch(spaceid) { diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 9216cfb5cdc..0f79420d3a7 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -3084,11 +3084,11 @@ void ED_operatortypes_uvedit(void) WM_operatortype_append(UV_OT_tile_set); } -void ED_keymap_uvedit(wmWindowManager *wm) +void ED_keymap_uvedit(wmKeyConfig *keyconf) { wmKeyMap *keymap; - keymap= WM_keymap_find(wm, "UVEdit", 0, 0); + keymap= WM_keymap_find(keyconf, "UVEdit", 0, 0); keymap->poll= ED_operator_uvedit; /* pick selection */ @@ -3129,6 +3129,6 @@ void ED_keymap_uvedit(wmWindowManager *wm) WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0); - transform_keymap_for_space(wm, keymap, SPACE_IMAGE); + transform_keymap_for_space(keyconf, keymap, SPACE_IMAGE); } diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 5aa1aa6dfff..6a1b22e1ed5 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -308,6 +308,8 @@ typedef struct UserDef { struct ListBase themes; struct ListBase uifonts; struct ListBase uistyles; + struct ListBase keymaps; + char keyconfigstr[64]; short undosteps; short undomemory; @@ -345,6 +347,14 @@ extern UserDef U; /* from blenkernel blender.c */ /* ***************** USERDEF ****************** */ +/* userpref/section */ +#define USER_SECTION_INTERFACE 0 +#define USER_SECTION_EDIT 1 +#define USER_SECTION_FILE 2 +#define USER_SECTION_SYSTEM 3 +#define USER_SECTION_THEME 4 +#define USER_SECTION_INPUT 5 + /* flag */ #define USER_AUTOSAVE (1 << 0) #define USER_AUTOGRABGRID (1 << 1) diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index ea9d0e86c38..2b986d6d802 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -42,6 +42,7 @@ struct wmGesture; struct wmOperatorType; struct wmOperator; struct wmKeyMap; +struct wmKeyConfig; /* forwards */ struct bContext; @@ -120,9 +121,9 @@ typedef struct wmWindowManager { ListBase paintcursors; /* extra overlay cursors to draw, like circles */ - /* used keymaps, optionally/partially saved */ - ListBase keymaps; - + ListBase keyconfigs; /* known key configurations */ + struct wmKeyConfig *defaultconf; /* default configuration, not saved */ + int defaultactmap, pad2; /* active keymap from default for editing */ } wmWindowManager; /* wmWindowManager.initialized */ @@ -234,44 +235,70 @@ typedef struct wmOperatorType { /* partial copy of the event, for matching by eventhandler */ -typedef struct wmKeymapItem { - struct wmKeymapItem *next, *prev; +typedef struct wmKeyMapItem { + struct wmKeyMapItem *next, *prev; + /* operator */ char idname[64]; /* used to retrieve operator type pointer */ - struct PointerRNA *ptr; /* rna pointer to access properties */ + IDProperty *properties; /* operator properties */ + /* modal */ + short propvalue; /* if used, the item is from modal map */ + + /* event */ short type; /* event code itself */ short val; /* 0=any, 1=click, 2=release, or wheelvalue, or... */ short shift, ctrl, alt, oskey; /* oskey is apple or windowskey, value denotes order of pressed */ short keymodifier; /* rawkey modifier */ - short propvalue; /* if used, the item is from modal map */ - - short inactive; /* if set, deactivated item */ - short maptype; /* keymap editor */ - short pad2, pad3; -} wmKeymapItem; + /* flag: inactive, expanded */ + short flag; + /* runtime */ + short maptype, pad[2]; /* keymap editor */ + struct PointerRNA *ptr; /* rna pointer to access properties */ +} wmKeyMapItem; + +/* wmKeyMapItem.flag */ +#define KMI_INACTIVE 1 +#define KMI_EXPANDED 2 /* stored in WM, the actively used keymaps */ typedef struct wmKeyMap { struct wmKeyMap *next, *prev; - ListBase keymap; + ListBase items; - char nameid[64]; /* global editor keymaps, or for more per space/region */ + char idname[64]; /* global editor keymaps, or for more per space/region */ short spaceid; /* same IDs as in DNA_space_types.h */ short regionid; /* see above */ - short is_modal; /* modal map, not using operatornames */ + short flag; /* general flags */ short pad; - void *items; /* struct EnumPropertyItem for now */ - - /* verify if the keymap is enabled in the current context */ - int (*poll)(struct bContext *); + /* runtime */ + int (*poll)(struct bContext *); /* verify if enabled in the current context */ + void *modal_items; /* for modal, EnumPropertyItem for now */ } wmKeyMap; +/* wmKeyMap.flag */ +#define KEYMAP_MODAL 1 /* modal map, not using operatornames */ +#define KEYMAP_USER 2 /* user created keymap */ + +typedef struct wmKeyConfig { + struct wmKeyConfig *next, *prev; + + char idname[64]; /* unique name */ + char basename[64]; /* idname of configuration this is derives from, "" if none */ + + ListBase keymaps; + int actkeymap, flag; +} wmKeyConfig; + +/* wmKeyConfig.flag */ +#define KEYCONF_TWOBUTTONMOUSE (1 << 1) +#define KEYCONF_LMOUSESELECT (1 << 2) +#define KEYCONF_NONUMPAD (1 << 3) /* this one is the operator itself, stored in files for macros etc */ /* operator + operatortype should be able to redo entirely, but for different contextes */ diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 9ea7725b855..810fb110f7a 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -56,6 +56,7 @@ extern StructRNA RNA_Area; extern StructRNA RNA_AreaLamp; extern StructRNA RNA_Armature; extern StructRNA RNA_ArmatureModifier; +extern StructRNA RNA_ArmatureSensor; extern StructRNA RNA_ArrayModifier; extern StructRNA RNA_BackgroundImage; extern StructRNA RNA_BevelModifier; @@ -76,6 +77,7 @@ extern StructRNA RNA_BoneGroup; extern StructRNA RNA_BooleanModifier; extern StructRNA RNA_BooleanProperty; extern StructRNA RNA_Brush; +extern StructRNA RNA_BrushTextureSlot; extern StructRNA RNA_BuildModifier; extern StructRNA RNA_Camera; extern StructRNA RNA_CastModifier; @@ -99,7 +101,8 @@ extern StructRNA RNA_CompositorNodeBilateralblur; extern StructRNA RNA_CompositorNodeBlur; extern StructRNA RNA_CompositorNodeBrightContrast; extern StructRNA RNA_CompositorNodeChannelMatte; -extern StructRNA RNA_CompositorNodeChroma; +extern StructRNA RNA_CompositorNodeChromaMatte; +extern StructRNA RNA_CompositorNodeColorMatte; extern StructRNA RNA_CompositorNodeColorSpill; extern StructRNA RNA_CompositorNodeCombHSVA; extern StructRNA RNA_CompositorNodeCombRGBA; @@ -114,6 +117,7 @@ extern StructRNA RNA_CompositorNodeDefocus; extern StructRNA RNA_CompositorNodeDiffMatte; extern StructRNA RNA_CompositorNodeDilateErode; extern StructRNA RNA_CompositorNodeDisplace; +extern StructRNA RNA_CompositorNodeDistanceMatte; extern StructRNA RNA_CompositorNodeFilter; extern StructRNA RNA_CompositorNodeFlip; extern StructRNA RNA_CompositorNodeGamma; @@ -123,6 +127,7 @@ extern StructRNA RNA_CompositorNodeIDMask; extern StructRNA RNA_CompositorNodeImage; extern StructRNA RNA_CompositorNodeInvert; extern StructRNA RNA_CompositorNodeLensdist; +extern StructRNA RNA_CompositorNodeLevels; extern StructRNA RNA_CompositorNodeLumaMatte; extern StructRNA RNA_CompositorNodeMapUV; extern StructRNA RNA_CompositorNodeMapValue; @@ -174,9 +179,11 @@ extern StructRNA RNA_DistortedNoiseTexture; extern StructRNA RNA_DomainFluidSettings; extern StructRNA RNA_Driver; extern StructRNA RNA_DriverTarget; +extern StructRNA RNA_DupliObject; extern StructRNA RNA_EdgeSplitModifier; extern StructRNA RNA_EditBone; extern StructRNA RNA_EffectSequence; +extern StructRNA RNA_EffectorWeights; extern StructRNA RNA_EnumProperty; extern StructRNA RNA_EnumPropertyItem; extern StructRNA RNA_EnvironmentMap; @@ -204,6 +211,10 @@ extern StructRNA RNA_FluidSettings; extern StructRNA RNA_FluidSimulationModifier; extern StructRNA RNA_FollowPathConstraint; extern StructRNA RNA_Function; +extern StructRNA RNA_GPencilFrame; +extern StructRNA RNA_GPencilLayer; +extern StructRNA RNA_GPencilStroke; +extern StructRNA RNA_GPencilStrokePoint; extern StructRNA RNA_GameBooleanProperty; extern StructRNA RNA_GameFloatProperty; extern StructRNA RNA_GameIntProperty; @@ -214,10 +225,6 @@ extern StructRNA RNA_GameStringProperty; extern StructRNA RNA_GameTimerProperty; extern StructRNA RNA_GlowSequence; extern StructRNA RNA_GreasePencil; -extern StructRNA RNA_GPencilLayer; -extern StructRNA RNA_GPencilFrame; -extern StructRNA RNA_GPencilStroke; -extern StructRNA RNA_GPencilStrokePoint; extern StructRNA RNA_Group; extern StructRNA RNA_Header; extern StructRNA RNA_HemiLamp; @@ -225,6 +232,7 @@ extern StructRNA RNA_HookModifier; extern StructRNA RNA_ID; extern StructRNA RNA_IDProperty; extern StructRNA RNA_IDPropertyGroup; +extern StructRNA RNA_IKParam; extern StructRNA RNA_Image; extern StructRNA RNA_ImagePaint; extern StructRNA RNA_ImageSequence; @@ -232,8 +240,12 @@ extern StructRNA RNA_ImageTexture; extern StructRNA RNA_ImageUser; extern StructRNA RNA_InflowFluidSettings; extern StructRNA RNA_IntProperty; +extern StructRNA RNA_Itasc; extern StructRNA RNA_JoystickSensor; extern StructRNA RNA_Key; +extern StructRNA RNA_KeyConfig; +extern StructRNA RNA_KeyMap; +extern StructRNA RNA_KeyMapItem; extern StructRNA RNA_KeyboardSensor; extern StructRNA RNA_KeyingSet; extern StructRNA RNA_KeyingSetPath; @@ -263,6 +275,7 @@ extern StructRNA RNA_MaterialSlot; extern StructRNA RNA_MaterialStrand; extern StructRNA RNA_MaterialSubsurfaceScattering; extern StructRNA RNA_MaterialTextureSlot; +extern StructRNA RNA_MaterialVolume; extern StructRNA RNA_Menu; extern StructRNA RNA_Mesh; extern StructRNA RNA_MeshColor; @@ -313,6 +326,7 @@ extern StructRNA RNA_Paint; extern StructRNA RNA_Panel; extern StructRNA RNA_Particle; extern StructRNA RNA_ParticleBrush; +extern StructRNA RNA_ParticleDupliWeight; extern StructRNA RNA_ParticleEdit; extern StructRNA RNA_ParticleFluidSettings; extern StructRNA RNA_ParticleHairKey; @@ -327,13 +341,12 @@ extern StructRNA RNA_PluginTexture; extern StructRNA RNA_PointCache; extern StructRNA RNA_PointDensity; extern StructRNA RNA_PointDensityTexture; -extern StructRNA RNA_PointerProperty; extern StructRNA RNA_PointLamp; +extern StructRNA RNA_PointerProperty; extern StructRNA RNA_Pose; extern StructRNA RNA_PoseChannel; extern StructRNA RNA_Property; extern StructRNA RNA_PropertySensor; -extern StructRNA RNA_ArmatureSensor; extern StructRNA RNA_PythonConstraint; extern StructRNA RNA_PythonController; extern StructRNA RNA_RadarSensor; @@ -344,7 +357,6 @@ extern StructRNA RNA_RenderEngine; extern StructRNA RNA_RenderLayer; extern StructRNA RNA_RenderPass; extern StructRNA RNA_RenderResult; -extern StructRNA RNA_RenderValue; extern StructRNA RNA_RigidBodyJointConstraint; extern StructRNA RNA_Scene; extern StructRNA RNA_SceneGameData; @@ -492,12 +504,12 @@ extern StructRNA RNA_TransformSequence; extern StructRNA RNA_UILayout; extern StructRNA RNA_UIListItem; extern StructRNA RNA_UVProjectModifier; +extern StructRNA RNA_UVProjector; extern StructRNA RNA_UnitSettings; extern StructRNA RNA_UnknownType; extern StructRNA RNA_UserPreferences; extern StructRNA RNA_UserPreferencesEdit; extern StructRNA RNA_UserPreferencesFilePaths; -extern StructRNA RNA_UserPreferencesLanguage; extern StructRNA RNA_UserPreferencesSystem; extern StructRNA RNA_UserPreferencesView; extern StructRNA RNA_UserSolidLight; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index df447894830..576f5cbb984 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -142,6 +142,9 @@ typedef enum PropertyFlag { /* icon */ PROP_ICONS_CONSECUTIVE = 4096, + /* hidden in the user interface */ + PROP_HIDDEN = 524288, + /* function paramater flags */ PROP_REQUIRED = 4, PROP_RETURN = 8, diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index da467381c06..bec2025907a 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -2785,7 +2785,10 @@ int RNA_property_is_set(PointerRNA *ptr, const char *name) PropertyRNA *prop= RNA_struct_find_property(ptr, name); if(prop) { - return (rna_idproperty_find(ptr, name) != NULL); + if(prop->flag & PROP_IDPROPERTY) + return (rna_idproperty_find(ptr, name) != NULL); + else + return 1; } else { // printf("RNA_property_is_set: %s.%s not found.\n", ptr->type->identifier, name); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index cc86da18a0b..f3fb1244565 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -667,6 +667,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char * } prop= RNA_def_property(&srna->cont, "rna_type", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_HIDDEN); RNA_def_property_ui_text(prop, "RNA", "RNA type definition."); if(DefRNA.preprocess) { diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index 1ebf03425d4..23592212f68 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -203,7 +203,9 @@ void rna_TextureSlot_update(struct bContext *C, struct PointerRNA *ptr); void RNA_api_action(StructRNA *srna); void RNA_api_image(struct StructRNA *srna); +void RNA_api_keyconfig(struct StructRNA *srna); void RNA_api_keyingset(struct StructRNA *srna); +void RNA_api_keymap(struct StructRNA *srna); void RNA_api_main(struct StructRNA *srna); void RNA_api_material(StructRNA *srna); void RNA_api_mesh(struct StructRNA *srna); @@ -213,7 +215,6 @@ void RNA_api_text(struct StructRNA *srna); void RNA_api_ui_layout(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); - /* ID Properties */ extern StringPropertyRNA rna_IDProperty_string; diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 17846651c3b..436efbcb2cf 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -37,7 +37,7 @@ #ifdef RNA_RUNTIME -static void rna_uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int expand, int slider, int toggle, int icon_only) +static void rna_uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, char *propname, int expand, int slider, int toggle, int icon_only, int event, int full_event) { int flag= 0; @@ -45,6 +45,8 @@ static void rna_uiItemR(uiLayout *layout, char *name, int icon, PointerRNA *ptr, flag |= (expand)? UI_ITEM_R_EXPAND: 0; flag |= (toggle)? UI_ITEM_R_TOGGLE: 0; flag |= (icon_only)? UI_ITEM_R_ICON_ONLY: 0; + flag |= (event)? UI_ITEM_R_EVENT: 0; + flag |= (full_event)? UI_ITEM_R_FULL_EVENT: 0; uiItemR(layout, name, icon, ptr, propname, flag); } @@ -147,6 +149,8 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_boolean(func, "slider", 0, "", "Use slider widget for numeric values."); RNA_def_boolean(func, "toggle", 0, "", "Use toggle widget for boolean values."); RNA_def_boolean(func, "icon_only", 0, "", "Draw only icons in buttons, no text."); + RNA_def_boolean(func, "event", 0, "", "Use button to input key events."); + RNA_def_boolean(func, "full_event", 0, "", "Use button to input full events including modifiers."); func= RNA_def_function(srna, "items_enumR", "uiItemsEnumR"); api_ui_item_rna_common(func); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 8f999300c71..3e3ed669e02 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1977,68 +1977,68 @@ static void rna_def_userdef_system(BlenderRNA *brna) StructRNA *srna; static EnumPropertyItem gl_texture_clamp_items[] = { - {0, "GL_CLAMP_OFF", 0, "Off", ""}, - {8192, "GL_CLAMP_8192", 0, "8192", ""}, - {4096, "GL_CLAMP_4096", 0, "4096", ""}, - {2048, "GL_CLAMP_2048", 0, "2048", ""}, - {1024, "GL_CLAMP_1024", 0, "1024", ""}, - {512, "GL_CLAMP_512", 0, "512", ""}, - {256, "GL_CLAMP_256", 0, "256", ""}, - {128, "GL_CLAMP_128", 0, "128", ""}, + {0, "CLAMP_OFF", 0, "Off", ""}, + {8192, "CLAMP_8192", 0, "8192", ""}, + {4096, "CLAMP_4096", 0, "4096", ""}, + {2048, "CLAMP_2048", 0, "2048", ""}, + {1024, "CLAMP_1024", 0, "1024", ""}, + {512, "CLAMP_512", 0, "512", ""}, + {256, "CLAMP_256", 0, "256", ""}, + {128, "CLAMP_128", 0, "128", ""}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem audio_mixing_samples_items[] = { - {256, "AUDIO_SAMPLES_256", 0, "256", "Set audio mixing buffer size to 256 samples"}, - {512, "AUDIO_SAMPLES_512", 0, "512", "Set audio mixing buffer size to 512 samples"}, - {1024, "AUDIO_SAMPLES_1024", 0, "1024", "Set audio mixing buffer size to 1024 samples"}, - {2048, "AUDIO_SAMPLES_2048", 0, "2048", "Set audio mixing buffer size to 2048 samples"}, - {4096, "AUDIO_SAMPLES_4096", 0, "4096", "Set audio mixing buffer size to 4096 samples"}, - {8192, "AUDIO_SAMPLES_8192", 0, "8192", "Set audio mixing buffer size to 8192 samples"}, - {16384, "AUDIO_SAMPLES_16384", 0, "16384", "Set audio mixing buffer size to 16384 samples"}, - {32768, "AUDIO_SAMPLES_32768", 0, "32768", "Set audio mixing buffer size to 32768 samples"}, + {256, "SAMPLES_256", 0, "256", "Set audio mixing buffer size to 256 samples"}, + {512, "SAMPLES_512", 0, "512", "Set audio mixing buffer size to 512 samples"}, + {1024, "SAMPLES_1024", 0, "1024", "Set audio mixing buffer size to 1024 samples"}, + {2048, "SAMPLES_2048", 0, "2048", "Set audio mixing buffer size to 2048 samples"}, + {4096, "SAMPLES_4096", 0, "4096", "Set audio mixing buffer size to 4096 samples"}, + {8192, "SAMPLES_8192", 0, "8192", "Set audio mixing buffer size to 8192 samples"}, + {16384, "SAMPLES_16384", 0, "16384", "Set audio mixing buffer size to 16384 samples"}, + {32768, "SAMPLES_32768", 0, "32768", "Set audio mixing buffer size to 32768 samples"}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem audio_device_items[] = { - {0, "AUDIO_DEVICE_NULL", 0, "No Audio", "Null device - there will be no audio output."}, + {0, "NONE", 0, "None", "Null device - there will be no audio output."}, #ifdef WITH_SDL - {1, "AUDIO_DEVICE_SDL", 0, "SDL", "SDL device - simple direct media layer, recommended for sequencer usage."}, + {1, "SDL", 0, "SDL", "SDL device - simple direct media layer, recommended for sequencer usage."}, #endif #ifdef WITH_OPENAL - {2, "AUDIO_DEVICE_OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage."}, + {2, "OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage."}, #endif #ifdef WITH_JACK - {3, "AUDIO_DEVICE_JACK", 0, "Jack", "Jack device - open source pro audio, recommended for pro audio users."}, + {3, "JACK", 0, "Jack", "Jack device - open source pro audio, recommended for pro audio users."}, #endif {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem audio_rate_items[] = { -// {8000, "AUDIO_RATE_8000", 0, "8 kHz", "Set audio sampling rate to 8000 samples per second."}, -// {11025, "AUDIO_RATE_11025", 0, "11.025 kHz", "Set audio sampling rate to 11025 samples per second."}, -// {16000, "AUDIO_RATE_16000", 0, "16 kHz", "Set audio sampling rate to 16000 samples per second."}, -// {22050, "AUDIO_RATE_22050", 0, "22.05 kHz", "Set audio sampling rate to 22050 samples per second."}, -// {32000, "AUDIO_RATE_32000", 0, "32 kHz", "Set audio sampling rate to 32000 samples per second."}, - {44100, "AUDIO_RATE_44100", 0, "44.1 kHz", "Set audio sampling rate to 44100 samples per second."}, - {48000, "AUDIO_RATE_48000", 0, "48 kHz", "Set audio sampling rate to 48000 samples per second."}, -// {88200, "AUDIO_RATE_88200", 0, "88.2 kHz", "Set audio sampling rate to 88200 samples per second."}, - {96000, "AUDIO_RATE_96000", 0, "96 kHz", "Set audio sampling rate to 96000 samples per second."}, - {192000, "AUDIO_RATE_192000", 0, "192 kHz", "Set audio sampling rate to 192000 samples per second."}, +// {8000, "RATE_8000", 0, "8 kHz", "Set audio sampling rate to 8000 samples per second."}, +// {11025, "RATE_11025", 0, "11.025 kHz", "Set audio sampling rate to 11025 samples per second."}, +// {16000, "RATE_16000", 0, "16 kHz", "Set audio sampling rate to 16000 samples per second."}, +// {22050, "RATE_22050", 0, "22.05 kHz", "Set audio sampling rate to 22050 samples per second."}, +// {32000, "RATE_32000", 0, "32 kHz", "Set audio sampling rate to 32000 samples per second."}, + {44100, "RATE_44100", 0, "44.1 kHz", "Set audio sampling rate to 44100 samples per second."}, + {48000, "RATE_48000", 0, "48 kHz", "Set audio sampling rate to 48000 samples per second."}, +// {88200, "RATE_88200", 0, "88.2 kHz", "Set audio sampling rate to 88200 samples per second."}, + {96000, "RATE_96000", 0, "96 kHz", "Set audio sampling rate to 96000 samples per second."}, + {192000, "RATE_192000", 0, "192 kHz", "Set audio sampling rate to 192000 samples per second."}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem audio_format_items[] = { - {0x01, "AUDIO_FORMAT_U8", 0, "8-bit Unsigned", "Set audio sample format to 8 bit unsigned integer."}, - {0x12, "AUDIO_FORMAT_S16", 0, "16-bit Signed", "Set audio sample format to 16 bit signed integer."}, - {0x13, "AUDIO_FORMAT_S24", 0, "24-bit Signed", "Set audio sample format to 24 bit signed integer."}, - {0x14, "AUDIO_FORMAT_S32", 0, "32-bit Signed", "Set audio sample format to 32 bit signed integer."}, - {0x24, "AUDIO_FORMAT_FLOAT", 0, "32-bit Float", "Set audio sample format to 32 bit float."}, - {0x28, "AUDIO_FORMAT_DOUBLE", 0, "64-bit Float", "Set audio sample format to 64 bit float."}, + {0x01, "U8", 0, "8-bit Unsigned", "Set audio sample format to 8 bit unsigned integer."}, + {0x12, "S16", 0, "16-bit Signed", "Set audio sample format to 16 bit signed integer."}, + {0x13, "S24", 0, "24-bit Signed", "Set audio sample format to 24 bit signed integer."}, + {0x14, "S32", 0, "32-bit Signed", "Set audio sample format to 32 bit signed integer."}, + {0x24, "FLOAT", 0, "32-bit Float", "Set audio sample format to 32 bit float."}, + {0x28, "DOUBLE", 0, "64-bit Float", "Set audio sample format to 64 bit float."}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem audio_channel_items[] = { - {1, "AUDIO_CHANNELS_MONO", 0, "Mono", "Set audio channels to mono."}, - {2, "AUDIO_CHANNELS_STEREO", 0, "Stereo", "Set audio channels to stereo."}, - {4, "AUDIO_CHANNELS_SURROUND4", 0, "4 Channels", "Set audio channels to 4 channels."}, - {6, "AUDIO_CHANNELS_SURROUND51", 0, "5.1 Surround", "Set audio channels to 5.1 surround sound."}, - {8, "AUDIO_CHANNELS_SURROUND71", 0, "7.1 Surround", "Set audio channels to 7.1 surround sound."}, + {1, "MONO", 0, "Mono", "Set audio channels to mono."}, + {2, "STEREO", 0, "Stereo", "Set audio channels to stereo."}, + {4, "SURROUND4", 0, "4 Channels", "Set audio channels to 4 channels."}, + {6, "SURROUND51", 0, "5.1 Surround", "Set audio channels to 5.1 surround sound."}, + {8, "SURROUND71", 0, "7.1 Surround", "Set audio channels to 7.1 surround sound."}, {0, NULL, 0, NULL, NULL}}; static EnumPropertyItem draw_method_items[] = { @@ -2340,11 +2340,12 @@ void RNA_def_userdef(BlenderRNA *brna) PropertyRNA *prop; static EnumPropertyItem user_pref_sections[] = { - {0, "VIEW_CONTROLS", 0, "View", ""}, - {1, "EDIT_METHODS", 0, "Editing", ""}, - {2, "FILE_PATHS", 0, "File", ""}, - {3, "SYSTEM_OPENGL", 0, "System", ""}, -// {4, "THEMES", 0, "Themes", ""}, // Leave this out until we figure out a way to manage themes in the prefs. + {USER_SECTION_INTERFACE, "INTERFACE", 0, "Interface", ""}, + {USER_SECTION_EDIT, "EDITING", 0, "Editing", ""}, + {USER_SECTION_INPUT, "INPUT", 0, "Input", ""}, +// {USER_SECTION_THEME, "THEMES", 0, "Themes", ""}, // Leave this out until we figure out a way to manage themes in the prefs. + {USER_SECTION_FILE, "FILES", 0, "File", ""}, + {USER_SECTION_SYSTEM, "SYSTEM", 0, "System", ""}, {0, NULL, 0, NULL, NULL}}; rna_def_userdef_dothemes(brna); @@ -2358,6 +2359,7 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "userpref"); RNA_def_property_enum_items(prop, user_pref_sections); RNA_def_property_ui_text(prop, "Active Section", "Active section of the user preferences shown in the user interface."); + RNA_def_property_update(prop, 0, "rna_userdef_update"); prop= RNA_def_property(srna, "themes", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "themes", NULL); diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 0dd9e3aed42..82b244fa702 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -24,14 +24,37 @@ #include +#include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "RNA_types.h" #include "rna_internal.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" -#include "WM_types.h" /* wmEvent */ +#include "WM_types.h" + +EnumPropertyItem event_keymouse_value_items[] = { + {KM_ANY, "ANY", 0, "Any", ""}, + {KM_PRESS, "PRESS", 0, "Press", ""}, + {KM_RELEASE, "RELEASE", 0, "Release", ""}, + {0, NULL, 0, NULL, NULL}}; + +EnumPropertyItem event_tweak_value_items[]= { + {KM_ANY, "ANY", 0, "Any", ""}, + {EVT_GESTURE_N, "NORTH", 0, "North", ""}, + {EVT_GESTURE_NE, "NORTH_EAST", 0, "North-East", ""}, + {EVT_GESTURE_E, "EAST", 0, "East", ""}, + {EVT_GESTURE_SE, "SOUTH_EAST", 0, "South-East", ""}, + {EVT_GESTURE_S, "SOUTH", 0, "South", ""}, + {EVT_GESTURE_SW, "SOUTH_WEST", 0, "South-West", ""}, + {EVT_GESTURE_W, "WEST", 0, "West", ""}, + {EVT_GESTURE_NW, "NORTH_WEST", 0, "North-West", ""}, + {0, NULL, 0, NULL, NULL}}; EnumPropertyItem event_value_items[] = { {KM_ANY, "ANY", 0, "Any", ""}, @@ -40,9 +63,43 @@ EnumPropertyItem event_value_items[] = { {KM_RELEASE, "RELEASE", 0, "Release", ""}, {0, NULL, 0, NULL, NULL}}; +EnumPropertyItem event_tweak_type_items[]= { + {EVT_TWEAK_L, "EVT_TWEAK_L", 0, "Left", ""}, + {EVT_TWEAK_M, "EVT_TWEAK_M", 0, "Middle", ""}, + {EVT_TWEAK_R, "EVT_TWEAK_R", 0, "Right", ""}, + {EVT_TWEAK_A, "EVT_TWEAK_A", 0, "Action", ""}, + {EVT_TWEAK_S, "EVT_TWEAK_S", 0, "Select", ""}, + {0, NULL, 0, NULL, NULL}}; + +EnumPropertyItem event_mouse_type_items[]= { + {LEFTMOUSE, "LEFTMOUSE", 0, "Left", ""}, + {MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle", ""}, + {RIGHTMOUSE, "RIGHTMOUSE", 0, "Right", ""}, + {BUTTON4MOUSE, "BUTTON4MOUSE", 0, "Button4", ""}, + {BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5", ""}, + {ACTIONMOUSE, "ACTIONMOUSE", 0, "Action", ""}, + {SELECTMOUSE, "SELECTMOUSE", 0, "Select", ""}, + {0, "", 0, NULL, NULL}, + {MOUSEMOVE, "MOUSEMOVE", 0, "Move", ""}, + {0, "", 0, NULL, NULL}, + {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""}, + {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""}, + {WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", ""}, + {WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, "Wheel Out", ""}, + {0, NULL, 0, NULL, NULL}}; + +EnumPropertyItem event_timer_type_items[]= { + {TIMER, "TIMER", 0, "Timer", ""}, + {TIMER0, "TIMER0", 0, "Timer 0", ""}, + {TIMER1, "TIMER1", 0, "Timer 1", ""}, + {TIMER2, "TIMER2", 0, "Timer 2", ""}, + {TIMERJOBS, "JOBS_TIMER", 0, "Jobs Timer", ""}, + {0, NULL, 0, NULL, NULL}}; + /* not returned: CAPSLOCKKEY, UNKNOWNKEY, GRLESSKEY */ EnumPropertyItem event_type_items[] = { + {0, "NONE", 0, "", ""}, {LEFTMOUSE, "LEFTMOUSE", 0, "Left Mouse", ""}, {MIDDLEMOUSE, "MIDDLEMOUSE", 0, "Middle Mouse", ""}, {RIGHTMOUSE, "RIGHTMOUSE", 0, "Right Mouse", ""}, @@ -50,20 +107,20 @@ EnumPropertyItem event_type_items[] = { {BUTTON5MOUSE, "BUTTON5MOUSE", 0, "Button5 Mouse", ""}, {ACTIONMOUSE, "ACTIONMOUSE", 0, "Action Mouse", ""}, {SELECTMOUSE, "SELECTMOUSE", 0, "Select Mouse", ""}, - + {0, "", 0, NULL, NULL}, {MOUSEMOVE, "MOUSEMOVE", 0, "Mouse Move", ""}, - + {0, "", 0, NULL, NULL}, {WHEELUPMOUSE, "WHEELUPMOUSE", 0, "Wheel Up", ""}, {WHEELDOWNMOUSE, "WHEELDOWNMOUSE", 0, "Wheel Down", ""}, {WHEELINMOUSE, "WHEELINMOUSE", 0, "Wheel In", ""}, {WHEELOUTMOUSE, "WHEELOUTMOUSE", 0, "Wheel Out", ""}, - + {0, "", 0, NULL, NULL}, {EVT_TWEAK_L, "EVT_TWEAK_L", 0, "Tweak Left", ""}, {EVT_TWEAK_M, "EVT_TWEAK_M", 0, "Tweak Middle", ""}, {EVT_TWEAK_R, "EVT_TWEAK_R", 0, "Tweak Right", ""}, {EVT_TWEAK_A, "EVT_TWEAK_A", 0, "Tweak Action", ""}, {EVT_TWEAK_S, "EVT_TWEAK_S", 0, "Tweak Select", ""}, - + {0, "", 0, NULL, NULL}, {AKEY, "A", 0, "A", ""}, {BKEY, "B", 0, "B", ""}, {CKEY, "C", 0, "C", ""}, @@ -90,7 +147,7 @@ EnumPropertyItem event_type_items[] = { {XKEY, "X", 0, "X", ""}, {YKEY, "Y", 0, "Y", ""}, {ZKEY, "Z", 0, "Z", ""}, - + {0, "", 0, NULL, NULL}, {ZEROKEY, "ZERO", 0, "0", ""}, {ONEKEY, "ONE", 0, "1", ""}, {TWOKEY, "TWO", 0, "2", ""}, @@ -101,16 +158,16 @@ EnumPropertyItem event_type_items[] = { {SEVENKEY, "SEVEN", 0, "7", ""}, {EIGHTKEY, "EIGHT", 0, "8", ""}, {NINEKEY, "NINE", 0, "9", ""}, - + {0, "", 0, NULL, NULL}, {LEFTCTRLKEY, "LEFT_CTRL", 0, "Left Ctrl", ""}, {LEFTALTKEY, "LEFT_ALT", 0, "Left Alt", ""}, {LEFTSHIFTKEY, "LEFT_SHIFT", 0, "Left Shift", ""}, {RIGHTALTKEY, "RIGHT_ALT", 0, "Right Alt", ""}, {RIGHTCTRLKEY, "RIGHT_CTRL", 0, "Right Ctrl", ""}, {RIGHTSHIFTKEY, "RIGHT_SHIFT", 0, "Right Shift", ""}, - + {0, "", 0, NULL, NULL}, {COMMANDKEY, "COMMAND", 0, "Command", ""}, - + {0, "", 0, NULL, NULL}, {ESCKEY, "ESC", 0, "Esc", ""}, {TABKEY, "TAB", 0, "Tab", ""}, {RETKEY, "RET", 0, "Return", ""}, @@ -167,8 +224,20 @@ EnumPropertyItem event_type_items[] = { {PAGEUPKEY, "PAGE_UP", 0, "Page Up", ""}, {PAGEDOWNKEY, "PAGE_DOWN", 0, "Page Down", ""}, {ENDKEY, "END", 0, "End", ""}, + {0, "", 0, NULL, NULL}, + {TIMER, "TIMER", 0, "Timer", ""}, + {TIMER0, "TIMER0", 0, "Timer 0", ""}, + {TIMER1, "TIMER1", 0, "Timer 1", ""}, + {TIMER2, "TIMER2", 0, "Timer 2", ""}, + {TIMERJOBS, "JOBS_TIMER", 0, "Jobs Timer", ""}, {0, NULL, 0, NULL, NULL}}; +#define KMI_TYPE_KEYBOARD 0 +#define KMI_TYPE_MOUSE 1 +#define KMI_TYPE_TWEAK 2 +#define KMI_TYPE_TEXTINPUT 3 +#define KMI_TYPE_TIMER 4 + #ifdef RNA_RUNTIME #include "WM_api.h" @@ -263,6 +332,156 @@ static void rna_Window_screen_update(bContext *C, PointerRNA *ptr) } } +static PointerRNA rna_KeyMapItem_properties_get(PointerRNA *ptr) +{ + wmKeyMapItem *kmi= ptr->data; + + if(kmi->ptr) + return *(kmi->ptr); + + //return rna_pointer_inherit_refine(ptr, &RNA_OperatorProperties, op->properties); + return PointerRNA_NULL; +} + +static int rna_wmKeyMapItem_map_type_get(PointerRNA *ptr) +{ + wmKeyMapItem *kmi= ptr->data; + + if(ISTIMER(kmi->type)) return KMI_TYPE_TIMER; + if(ISKEYBOARD(kmi->type)) return KMI_TYPE_KEYBOARD; + if(ISTWEAK(kmi->type)) return KMI_TYPE_TWEAK; + if(ISMOUSE(kmi->type)) return KMI_TYPE_MOUSE; + if(kmi->type == KM_TEXTINPUT) return KMI_TYPE_TEXTINPUT; + return KMI_TYPE_KEYBOARD; +} + +static void rna_wmKeyMapItem_map_type_set(PointerRNA *ptr, int value) +{ + wmKeyMapItem *kmi= ptr->data; + int map_type= rna_wmKeyMapItem_map_type_get(ptr); + + if(value != map_type) { + switch(value) { + case KMI_TYPE_KEYBOARD: + kmi->type= AKEY; + kmi->val= KM_PRESS; + break; + case KMI_TYPE_TWEAK: + kmi->type= EVT_TWEAK_L; + kmi->val= KM_ANY; + break; + case KMI_TYPE_MOUSE: + kmi->type= LEFTMOUSE; + kmi->val= KM_PRESS; + break; + case KMI_TYPE_TEXTINPUT: + kmi->type= KM_TEXTINPUT; + kmi->val= KM_NOTHING; + break; + case KMI_TYPE_TIMER: + kmi->type= TIMER; + kmi->val= KM_NOTHING; + break; + } + } +} + +static EnumPropertyItem *rna_KeyMapItem_type_itemf(bContext *C, PointerRNA *ptr, int *free) +{ + int map_type= rna_wmKeyMapItem_map_type_get(ptr); + + if(map_type == KMI_TYPE_MOUSE) return event_mouse_type_items; + if(map_type == KMI_TYPE_TWEAK) return event_tweak_type_items; + if(map_type == KMI_TYPE_TIMER) return event_timer_type_items; + else return event_type_items; +} + +static EnumPropertyItem *rna_KeyMapItem_value_itemf(bContext *C, PointerRNA *ptr, int *free) +{ + int map_type= rna_wmKeyMapItem_map_type_get(ptr); + + if(map_type == KMI_TYPE_MOUSE || map_type == KMI_TYPE_KEYBOARD) return event_keymouse_value_items; + if(map_type == KMI_TYPE_TWEAK) return event_tweak_value_items; + else return event_value_items; +} + +static PointerRNA rna_WindowManager_active_keyconfig_get(PointerRNA *ptr) +{ + wmWindowManager *wm= ptr->data; + wmKeyConfig *kc; + + for(kc=wm->keyconfigs.first; kc; kc=kc->next) + if(strcmp(kc->idname, U.keyconfigstr) == 0) + break; + + if(!kc) + kc= wm->defaultconf; + + return rna_pointer_inherit_refine(ptr, &RNA_KeyConfig, kc); +} + +static void rna_WindowManager_active_keyconfig_set(PointerRNA *ptr, PointerRNA value) +{ + wmKeyConfig *kc= value.data; + + if(kc) + BLI_strncpy(U.keyconfigstr, kc->idname, sizeof(U.keyconfigstr)); +} + +static PointerRNA rna_WindowManager_active_keymap_get(PointerRNA *ptr) +{ + wmWindowManager *wm= ptr->data; + wmKeyMap *km= NULL; + + if(wm->defaultconf) { + km= BLI_findlink(&wm->defaultconf->keymaps, wm->defaultactmap); + + if(!km) + km= wm->defaultconf->keymaps.first; + } + + return rna_pointer_inherit_refine(ptr, &RNA_KeyMap, WM_keymap_active(wm, km)); +} + +static void rna_WindowManager_active_keymap_set(PointerRNA *ptr, PointerRNA value) +{ + wmWindowManager *wm= ptr->data; + wmKeyMap *km= value.data; + int index; + + if(wm->defaultconf && km) { + km= WM_keymap_find(wm->defaultconf, km->idname, km->spaceid, km->regionid); + index= BLI_findindex(&wm->defaultconf->keymaps, km); + + if(index != -1) wm->defaultactmap= index; + else wm->defaultactmap= 0; + } +} + +static void rna_wmKeyMapItem_idname_get(PointerRNA *ptr, char *value) +{ + wmKeyMapItem *kmi= ptr->data; + WM_operator_py_idname(value, kmi->idname); +} + +static int rna_wmKeyMapItem_idname_length(PointerRNA *ptr) +{ + wmKeyMapItem *kmi= ptr->data; + char pyname[OP_MAX_TYPENAME]; + + WM_operator_py_idname(pyname, kmi->idname); + return strlen(pyname); +} + +static void rna_wmKeyMapItem_idname_set(PointerRNA *ptr, const char *value) +{ + wmKeyMapItem *kmi= ptr->data; + char idname[OP_MAX_TYPENAME]; + + WM_operator_bl_idname(idname, value); + BLI_strncpy(kmi->idname, idname, sizeof(kmi->idname)); +} + #else static void rna_def_operator(BlenderRNA *brna) @@ -434,9 +653,154 @@ static void rna_def_windowmanager(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Window"); RNA_def_property_ui_text(prop, "Windows", "Open windows."); + prop= RNA_def_property(srna, "keyconfigs", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "KeyConfig"); + RNA_def_property_ui_text(prop, "Key Configurations", "Registered key configurations."); + + prop= RNA_def_property(srna, "active_keyconfig", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "KeyConfig"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs(prop, "rna_WindowManager_active_keyconfig_get", "rna_WindowManager_active_keyconfig_set", 0); + RNA_def_property_ui_text(prop, "Active Key Configuration", ""); + + prop= RNA_def_property(srna, "default_keyconfig", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "defaultconf"); + RNA_def_property_struct_type(prop, "KeyConfig"); + RNA_def_property_ui_text(prop, "Default Key Configuration", ""); + + prop= RNA_def_property(srna, "active_keymap", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "KeyMap"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_pointer_funcs(prop, "rna_WindowManager_active_keymap_get", "rna_WindowManager_active_keymap_set", 0); + RNA_def_property_ui_text(prop, "Active Key Map", ""); + RNA_api_wm(srna); } +static void rna_def_keyconfig(BlenderRNA *brna) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *prop, *parm; + + static EnumPropertyItem map_type_items[] = { + {KMI_TYPE_KEYBOARD, "KEYBOARD", 0, "Keyboard", ""}, + {KMI_TYPE_TWEAK, "TWEAK", 0, "Tweak", ""}, + {KMI_TYPE_MOUSE, "MOUSE", 0, "Mouse", ""}, + {KMI_TYPE_TEXTINPUT, "TEXTINPUT", 0, "Text Input", ""}, + {KMI_TYPE_TIMER, "TIMER", 0, "Timer", ""}, + {0, NULL, 0, NULL, NULL}}; + + /* KeyConfig */ + srna= RNA_def_struct(brna, "KeyConfig", NULL); + RNA_def_struct_sdna(srna, "wmKeyConfig"); + RNA_def_struct_ui_text(srna, "Key Configuration", "Input configuration, including keymaps."); + + prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "idname"); + RNA_def_property_ui_text(prop, "Name", "Name of the key configuration."); + RNA_def_struct_name_property(srna, prop); + + prop= RNA_def_property(srna, "keymaps", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "KeyMap"); + RNA_def_property_ui_text(prop, "Key Maps", "Key maps configured as part of this configuration."); + + RNA_api_keyconfig(srna); + + /* KeyMap */ + srna= RNA_def_struct(brna, "KeyMap", NULL); + RNA_def_struct_sdna(srna, "wmKeyMap"); + RNA_def_struct_ui_text(srna, "Key Map", "Input configuration, including keymaps."); + + prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "idname"); + RNA_def_property_ui_text(prop, "Name", "Name of the key map."); + RNA_def_struct_name_property(srna, prop); + + prop= RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "spaceid"); + RNA_def_property_enum_items(prop, space_type_items); + RNA_def_property_ui_text(prop, "Space Type", "Optional space type keymap is associated with."); + + prop= RNA_def_property(srna, "region_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "regionid"); + RNA_def_property_enum_items(prop, region_type_items); + RNA_def_property_ui_text(prop, "Region Type", "Optional region type keymap is associated with."); + + prop= RNA_def_property(srna, "items", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "KeyMapItem"); + RNA_def_property_ui_text(prop, "Items", "Items in the keymap, linking an operator to an input event."); + + prop= RNA_def_property(srna, "user_defined", PROP_BOOLEAN, PROP_NEVER_NULL); + RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYMAP_USER); + RNA_def_property_ui_text(prop, "User Defined", "Keymap is defined by the user."); + + RNA_api_keymap(srna); + + /* KeyMapItem */ + srna= RNA_def_struct(brna, "KeyMapItem", NULL); + RNA_def_struct_sdna(srna, "wmKeyMapItem"); + RNA_def_struct_ui_text(srna, "Key Map Item", "Item in a Key Map."); + + prop= RNA_def_property(srna, "idname", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "idname"); + RNA_def_property_ui_text(prop, "Identifier", "Identifier of operator to call on input event."); + RNA_def_property_string_funcs(prop, "rna_wmKeyMapItem_idname_get", "rna_wmKeyMapItem_idname_length", "rna_wmKeyMapItem_idname_set"); + RNA_def_struct_name_property(srna, prop); + + prop= RNA_def_property(srna, "properties", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "OperatorProperties"); + RNA_def_property_pointer_funcs(prop, "rna_KeyMapItem_properties_get", NULL, NULL); + RNA_def_property_ui_text(prop, "Properties", "Properties to set when the operator is called."); + + prop= RNA_def_property(srna, "map_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "maptype"); + RNA_def_property_enum_items(prop, map_type_items); + RNA_def_property_enum_funcs(prop, "rna_wmKeyMapItem_map_type_get", "rna_wmKeyMapItem_map_type_set", NULL); + RNA_def_property_ui_text(prop, "Map Type", "Type of event mapping."); + + prop= RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_type_itemf"); + RNA_def_property_ui_text(prop, "Type", "Type of event."); + + prop= RNA_def_property(srna, "value", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "val"); + RNA_def_property_enum_items(prop, event_value_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_KeyMapItem_value_itemf"); + RNA_def_property_ui_text(prop, "Value", ""); + + prop= RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "shift", 0); + RNA_def_property_ui_text(prop, "Shift", "Shift key pressed."); + + prop= RNA_def_property(srna, "ctrl", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "ctrl", 0); + RNA_def_property_ui_text(prop, "Ctrl", "Control key pressed."); + + prop= RNA_def_property(srna, "alt", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "alt", 0); + RNA_def_property_ui_text(prop, "Alt", "Alt key pressed."); + + prop= RNA_def_property(srna, "oskey", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "oskey", 0); + RNA_def_property_ui_text(prop, "OS Key", "Operating system key pressed."); + + prop= RNA_def_property(srna, "key_modifier", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "keymodifier"); + RNA_def_property_enum_items(prop, event_type_items); + RNA_def_property_ui_text(prop, "Key Modifier", "Regular key pressed as a modifier."); + + prop= RNA_def_property(srna, "expanded", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", KMI_EXPANDED); + RNA_def_property_ui_text(prop, "Expanded", "Expanded in the user interface."); + + prop= RNA_def_property(srna, "active", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", KMI_INACTIVE); + RNA_def_property_ui_text(prop, "Active", "Activate or deactivate item."); +} + void RNA_def_wm(BlenderRNA *brna) { rna_def_operator(brna); @@ -445,6 +809,7 @@ void RNA_def_wm(BlenderRNA *brna) rna_def_event(brna); rna_def_window(brna); rna_def_windowmanager(brna); + rna_def_keyconfig(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index fd34d7c4d70..44c6967189d 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -31,25 +31,93 @@ #include "RNA_define.h" #include "RNA_types.h" +#include "RNA_enum_types.h" + +#include "DNA_screen_types.h" +#include "DNA_space_types.h" #ifdef RNA_RUNTIME #include "BKE_context.h" #include "WM_api.h" +#include "WM_types.h" + +static wmKeyMapItem *rna_KeyMap_add_item(wmKeyMap *km, char *idname, int type, int value, int shift, int ctrl, int alt, int oskey, int keymodifier) +{ + int modifier= 0; + + if(shift) modifier |= KM_SHIFT; + if(ctrl) modifier |= KM_CTRL; + if(alt) modifier |= KM_ALT; + if(oskey) modifier |= KM_OSKEY; + + return WM_keymap_add_item(km, idname, type, value, modifier, keymodifier); +} #else void RNA_api_wm(StructRNA *srna) { FunctionRNA *func; - PropertyRNA *prop; + PropertyRNA *parm; func= RNA_def_function(srna, "add_fileselect", "WM_event_add_fileselect"); RNA_def_function_flag(func, FUNC_NO_SELF|FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Show up the file selector."); - prop= RNA_def_pointer(func, "operator", "Operator", "", "Operator to call."); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm= RNA_def_pointer(func, "operator", "Operator", "", "Operator to call."); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "add_keyconfig", "WM_keyconfig_add"); + parm= RNA_def_string(func, "name", "", 0, "Name", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration."); + RNA_def_function_return(func, parm); +} + +void RNA_api_keyconfig(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func= RNA_def_function(srna, "add_keymap", "WM_keymap_find"); + parm= RNA_def_string(func, "name", "", 0, "Name", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_enum(func, "space_type", space_type_items, SPACE_EMPTY, "Space Type", ""); + RNA_def_enum(func, "region_type", region_type_items, RGN_TYPE_WINDOW, "Region Type", ""); + parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Added key map."); + RNA_def_function_return(func, parm); +} + +void RNA_api_keymap(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func= RNA_def_function(srna, "add_item", "rna_KeyMap_add_item"); + parm= RNA_def_string(func, "idname", "", 0, "Operator Identifier", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_enum(func, "type", event_type_items, 0, "Type", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + parm= RNA_def_enum(func, "value", event_value_items, 0, "Value", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_boolean(func, "shift", 0, "Shift", ""); + RNA_def_boolean(func, "ctrl", 0, "Ctrl", ""); + RNA_def_boolean(func, "alt", 0, "Alt", ""); + RNA_def_boolean(func, "oskey", 0, "OS Key", ""); + RNA_def_enum(func, "key_modifier", event_type_items, 0, "Key Modifier", ""); + parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", "Added key map item."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "remove_item", "WM_keymap_remove_item"); + parm= RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); + RNA_def_property_flag(parm, PROP_REQUIRED); + + func= RNA_def_function(srna, "copy_to_user", "WM_keymap_copy_to_user"); + parm= RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "User editable key map."); + RNA_def_function_return(func, parm); + + func= RNA_def_function(srna, "restore_to_default", "WM_keymap_restore_to_default"); } #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 42b905dc0d8..44b419e8ae9 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -433,7 +433,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) { PointerRNA newptr; newptr= RNA_property_pointer_get(ptr, prop); - if (newptr.data) { + if (newptr.type) { ret = pyrna_struct_CreatePyObject(&newptr); } else { ret = Py_None; @@ -1153,6 +1153,31 @@ static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA * self, PyObject *ar return PyBool_FromLong( insert_keyframe((ID *)self->ptr.data, NULL, NULL, path, index, cfra, 0)); } +static PyObject *pyrna_struct_is_property_set(BPy_StructRNA * self, PyObject *args) +{ + char *name; + + if (!PyArg_ParseTuple(args, "s:is_property_set", &name)) + return NULL; + + return PyBool_FromLong(RNA_property_is_set(&self->ptr, name)); +} + +static PyObject *pyrna_struct_is_property_hidden(BPy_StructRNA * self, PyObject *args) +{ + PropertyRNA *prop; + char *name; + int hidden; + + if (!PyArg_ParseTuple(args, "s:is_property_hidden", &name)) + return NULL; + + prop= RNA_struct_find_property(&self->ptr, name); + hidden= (prop)? (RNA_property_flag(prop) & PROP_HIDDEN): 1; + + return PyBool_FromLong(hidden); +} + static PyObject *pyrna_struct_dir(BPy_StructRNA * self) { @@ -1272,7 +1297,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) CTX_data_get(self->ptr.data, name, &newptr, &newlb); - if (newptr.data) { + if (newptr.type) { ret = pyrna_struct_CreatePyObject(&newptr); } else if (newlb.first) { @@ -1745,6 +1770,8 @@ static struct PyMethodDef pyrna_struct_methods[] = { /* maybe this become and ID function */ {"keyframe_insert", (PyCFunction)pyrna_struct_keyframe_insert, METH_VARARGS, NULL}, + {"is_property_set", (PyCFunction)pyrna_struct_is_property_set, METH_VARARGS, NULL}, + {"is_property_hidden", (PyCFunction)pyrna_struct_is_property_hidden, METH_VARARGS, NULL}, {"__dir__", (PyCFunction)pyrna_struct_dir, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 0054f151803..b29dbec6364 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -82,22 +82,30 @@ void WM_timecursor (struct wmWindow *win, int nr); void *WM_paint_cursor_activate(struct wmWindowManager *wm, int (*poll)(struct bContext *C), void (*draw)(struct bContext *C, int, int, void *customdata), void *customdata); void WM_paint_cursor_end(struct wmWindowManager *wm, void *handle); - /* keymap */ + /* keyconfig and keymap */ +wmKeyConfig *WM_keyconfig_add (struct wmWindowManager *wm, char *idname); +void WM_keyconfig_free (struct wmKeyConfig *keyconf); +void WM_keyconfig_userdef(struct wmWindowManager *wm); + void WM_keymap_init (struct bContext *C); -wmKeymapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, short type, - short val, int modifier, short keymodifier); -wmKeymapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, short type, - short val, int modifier, short keymodifier); -void WM_keymap_tweak (wmKeyMap *keymap, short type, short val, int modifier, short keymodifier); -wmKeyMap *WM_keymap_find (struct wmWindowManager *wm, const char *nameid, - short spaceid, short regionid); +void WM_keymap_free (struct wmKeyMap *keymap); -wmKeyMap *WM_modalkeymap_add(struct wmWindowManager *wm, const char *nameid, struct EnumPropertyItem *items); -wmKeyMap *WM_modalkeymap_get(struct wmWindowManager *wm, const char *nameid); -void WM_modalkeymap_add_item(wmKeyMap *km, short type, short val, int modifier, short keymodifier, short value); -void WM_modalkeymap_assign(wmKeyMap *km, const char *opname); +wmKeyMapItem *WM_keymap_verify_item(struct wmKeyMap *keymap, char *idname, int type, + int val, int modifier, int keymodifier); +wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, char *idname, int type, + int val, int modifier, int keymodifier); +void WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi); +char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len); -int WM_key_event_is_tweak(short type); +wmKeyMap *WM_keymap_find(struct wmKeyConfig *keyconf, char *idname, int spaceid, int regionid); +wmKeyMap *WM_keymap_active(struct wmWindowManager *wm, struct wmKeyMap *keymap); +wmKeyMap *WM_keymap_copy_to_user(struct wmKeyMap *keymap); +void WM_keymap_restore_to_default(struct wmKeyMap *keymap); + +wmKeyMap *WM_modalkeymap_add(struct wmKeyConfig *keyconf, char *idname, struct EnumPropertyItem *items); +wmKeyMap *WM_modalkeymap_get(struct wmKeyConfig *keyconf, char *idname); +void WM_modalkeymap_add_item(struct wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value); +void WM_modalkeymap_assign(struct wmKeyMap *km, char *opname); const char *WM_key_event_string(short type); char *WM_key_event_operator_string(const struct bContext *C, const char *opname, int opcontext, struct IDProperty *properties, char *str, int len); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 4405b52888d..a068f84ae29 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -132,12 +132,18 @@ void WM_keymap_init(bContext *C) { wmWindowManager *wm= CTX_wm_manager(C); + if(!wm->defaultconf) + wm->defaultconf= WM_keyconfig_add(wm, "Blender"); + if(wm && CTX_py_init_get(C) && (wm->initialized & WM_INIT_KEYMAP) == 0) { - wm_window_keymap(wm); - ED_spacetypes_keymap(wm); + /* create default key config */ + wm_window_keymap(wm->defaultconf); + ED_spacetypes_keymap(wm->defaultconf); wm->initialized |= WM_INIT_KEYMAP; } + + WM_keyconfig_userdef(wm); } void wm_check(bContext *C) @@ -151,15 +157,16 @@ void wm_check(bContext *C) } if(wm==NULL) return; if(wm->windows.first==NULL) return; + + /* case: fileread */ + if((wm->initialized & WM_INIT_WINDOW) == 0) + WM_keymap_init(C); /* case: no open windows at all, for old file reads */ wm_window_add_ghostwindows(wm); /* case: fileread */ if((wm->initialized & WM_INIT_WINDOW) == 0) { - - WM_keymap_init(C); - ED_screens_initialize(wm); wm->initialized |= WM_INIT_WINDOW; } @@ -211,8 +218,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) { wmWindow *win; wmOperator *op; - wmKeyMap *km; - wmKeymapItem *kmi; + wmKeyConfig *keyconf; while((win= wm->windows.first)) { BLI_remlink(&wm->windows, win); @@ -226,19 +232,11 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) WM_operator_free(op); } - while((km= wm->keymaps.first)) { - for(kmi=km->keymap.first; kmi; kmi=kmi->next) { - if(kmi->ptr) { - WM_operator_properties_free(kmi->ptr); - MEM_freeN(kmi->ptr); - } - } - - BLI_freelistN(&km->keymap); - BLI_remlink(&wm->keymaps, km); - MEM_freeN(km); + while((keyconf=wm->keyconfigs.first)) { + BLI_remlink(&wm->keyconfigs, keyconf); + WM_keyconfig_free(keyconf); } - + BLI_freelistN(&wm->queue); BLI_freelistN(&wm->paintcursors); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4a8aac4525d..ea73ed38123 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -725,16 +725,16 @@ static int wm_userdef_event_map(int kmitype) return kmitype; } -static int wm_eventmatch(wmEvent *winevent, wmKeymapItem *kmi) +static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi) { int kmitype= wm_userdef_event_map(kmi->type); - if(kmi->inactive) return 0; + if(kmi->flag & KMI_INACTIVE) return 0; /* exception for middlemouse emulation */ if((U.flag & USER_TWOBUTTONMOUSE) && (kmi->type == MIDDLEMOUSE)) { if(winevent->type == LEFTMOUSE && winevent->alt) { - wmKeymapItem tmp= *kmi; + wmKeyMapItem tmp= *kmi; tmp.type= winevent->type; tmp.alt= winevent->alt; @@ -784,9 +784,9 @@ static int wm_event_always_pass(wmEvent *event) static void wm_event_modalkeymap(wmOperator *op, wmEvent *event) { if(op->type->modalkeymap) { - wmKeymapItem *kmi; + wmKeyMapItem *kmi; - for(kmi= op->type->modalkeymap->keymap.first; kmi; kmi= kmi->next) { + for(kmi= op->type->modalkeymap->items.first; kmi; kmi= kmi->next) { if(wm_eventmatch(event, kmi)) { event->type= EVT_MODAL_MAP; @@ -1031,6 +1031,7 @@ static int handler_boundbox_test(wmEventHandler *handler, wmEvent *event) static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) { + wmWindowManager *wm= CTX_wm_manager(C); wmEventHandler *handler, *nexthandler; int action= WM_HANDLER_CONTINUE; int always_pass; @@ -1051,11 +1052,11 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) action= WM_HANDLER_BREAK; if(handler->keymap) { - wmKeyMap *keymap= handler->keymap; - wmKeymapItem *kmi; + wmKeyMap *keymap= WM_keymap_active(wm, handler->keymap); + wmKeyMapItem *kmi; if(!keymap->poll || keymap->poll(C)) { - for(kmi= keymap->keymap.first; kmi; kmi= kmi->next) { + for(kmi= keymap->items.first; kmi; kmi= kmi->next) { if(wm_eventmatch(event, kmi)) { event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 7d25fb8172e..3d3a6e46fb2 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -29,6 +29,7 @@ #include #include "DNA_screen_types.h" +#include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -52,9 +53,86 @@ #include "wm_event_system.h" #include "wm_event_types.h" +/* ********************* key config ***********************/ + +static void keymap_properties_set(wmKeyMapItem *kmi) +{ + if(!kmi->properties) { + IDPropertyTemplate val = {0}; + kmi->properties= IDP_New(IDP_GROUP, val, "wmKeyMapItemProperties"); + } + + if(!kmi->ptr) { + kmi->ptr= MEM_callocN(sizeof(PointerRNA), "wmKeyMapItemPtr"); + WM_operator_properties_create(kmi->ptr, kmi->idname); + } + + kmi->ptr->data= kmi->properties; +} + +wmKeyConfig *WM_keyconfig_add(wmWindowManager *wm, char *idname) +{ + wmKeyConfig *keyconf; + + keyconf= MEM_callocN(sizeof(wmKeyConfig), "wmKeyConfig"); + BLI_strncpy(keyconf->idname, idname, sizeof(keyconf->idname)); + BLI_addtail(&wm->keyconfigs, keyconf); + + return keyconf; +} + +void WM_keyconfig_free(wmKeyConfig *keyconf) +{ + wmKeyMap *km; + + while((km= keyconf->keymaps.first)) { + WM_keymap_free(km); + BLI_freelinkN(&keyconf->keymaps, km); + } + + MEM_freeN(keyconf); +} + +void WM_keyconfig_userdef(wmWindowManager *wm) +{ + wmKeyMap *km; + wmKeyMapItem *kmi; + + for(km=U.keymaps.first; km; km=km->next) + for(kmi=km->items.first; kmi; kmi=kmi->next) + keymap_properties_set(kmi); +} + +static wmKeyConfig *wm_keyconfig_list_find(ListBase *lb, char *idname) +{ + wmKeyConfig *kc; + + for(kc= lb->first; kc; kc= kc->next) + if(0==strncmp(idname, kc->idname, KMAP_MAX_NAME)) + return kc; + + return NULL; +} + +/* ************************ free ************************* */ + +void WM_keymap_free(wmKeyMap *keymap) +{ + wmKeyMapItem *kmi; + + for(kmi=keymap->items.first; kmi; kmi=kmi->next) { + if(kmi->ptr) { + WM_operator_properties_free(kmi->ptr); + MEM_freeN(kmi->ptr); + } + } + + BLI_freelistN(&keymap->items); +} + /* ***************** generic call, exported **************** */ -static void keymap_event_set(wmKeymapItem *kmi, short type, short val, int modifier, short keymodifier) +static void keymap_event_set(wmKeyMapItem *kmi, short type, short val, int modifier, short keymodifier) { kmi->type= type; kmi->val= val; @@ -87,26 +165,18 @@ static void keymap_event_set(wmKeymapItem *kmi, short type, short val, int modif } } -static void keymap_properties_set(wmKeymapItem *kmi) -{ - if(!kmi->ptr) { - kmi->ptr= MEM_callocN(sizeof(PointerRNA), "wmKeymapItemPtr"); - WM_operator_properties_create(kmi->ptr, kmi->idname); - } -} - /* if item was added, then bail out */ -wmKeymapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, short type, short val, int modifier, short keymodifier) +wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, int type, int val, int modifier, int keymodifier) { - wmKeymapItem *kmi; + wmKeyMapItem *kmi; - for(kmi= keymap->keymap.first; kmi; kmi= kmi->next) + for(kmi= keymap->items.first; kmi; kmi= kmi->next) if(strncmp(kmi->idname, idname, OP_MAX_TYPENAME)==0) break; if(kmi==NULL) { - kmi= MEM_callocN(sizeof(wmKeymapItem), "keymap entry"); + kmi= MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); - BLI_addtail(&keymap->keymap, kmi); + BLI_addtail(&keymap->items, kmi); BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME); keymap_event_set(kmi, type, val, modifier, keymodifier); @@ -116,11 +186,11 @@ wmKeymapItem *WM_keymap_verify_item(wmKeyMap *keymap, char *idname, short type, } /* always add item */ -wmKeymapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, short type, short val, int modifier, short keymodifier) +wmKeyMapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, int type, int val, int modifier, int keymodifier) { - wmKeymapItem *kmi= MEM_callocN(sizeof(wmKeymapItem), "keymap entry"); + wmKeyMapItem *kmi= MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); - BLI_addtail(&keymap->keymap, kmi); + BLI_addtail(&keymap->items, kmi); BLI_strncpy(kmi->idname, idname, OP_MAX_TYPENAME); keymap_event_set(kmi, type, val, modifier, keymodifier); @@ -128,27 +198,45 @@ wmKeymapItem *WM_keymap_add_item(wmKeyMap *keymap, char *idname, short type, sho return kmi; } +void WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi) +{ + if(BLI_findindex(&keymap->items, kmi) != -1) { + if(kmi->ptr) { + WM_operator_properties_free(kmi->ptr); + MEM_freeN(kmi->ptr); + } + BLI_freelinkN(&keymap->items, kmi); + } +} + /* ****************** storage in WM ************ */ /* name id's are for storing general or multiple keymaps, space/region ids are same as DNA_space_types.h */ /* gets free'd in wm.c */ -wmKeyMap *WM_keymap_find(wmWindowManager *wm, const char *nameid, short spaceid, short regionid) +static wmKeyMap *wm_keymap_list_find(ListBase *lb, char *idname, int spaceid, int regionid) { wmKeyMap *km; - - for(km= wm->keymaps.first; km; km= km->next) + + for(km= lb->first; km; km= km->next) if(km->spaceid==spaceid && km->regionid==regionid) - if(0==strncmp(nameid, km->nameid, KMAP_MAX_NAME)) + if(0==strncmp(idname, km->idname, KMAP_MAX_NAME)) return km; + return NULL; +} + +wmKeyMap *WM_keymap_find(wmKeyConfig *keyconf, char *idname, int spaceid, int regionid) +{ + wmKeyMap *km= wm_keymap_list_find(&keyconf->keymaps, idname, spaceid, regionid); + if(km==NULL) { km= MEM_callocN(sizeof(struct wmKeyMap), "keymap list"); - BLI_strncpy(km->nameid, nameid, KMAP_MAX_NAME); + BLI_strncpy(km->idname, idname, KMAP_MAX_NAME); km->spaceid= spaceid; km->regionid= regionid; - BLI_addtail(&wm->keymaps, km); + BLI_addtail(&keyconf->keymaps, km); } return km; @@ -158,39 +246,39 @@ wmKeyMap *WM_keymap_find(wmWindowManager *wm, const char *nameid, short spaceid, /* modal maps get linked to a running operator, and filter the keys before sending to modal() callback */ -wmKeyMap *WM_modalkeymap_add(wmWindowManager *wm, const char *nameid, EnumPropertyItem *items) +wmKeyMap *WM_modalkeymap_add(wmKeyConfig *keyconf, char *idname, EnumPropertyItem *items) { - wmKeyMap *km= WM_keymap_find(wm, nameid, 0, 0); - km->is_modal= 1; - km->items= items; + wmKeyMap *km= WM_keymap_find(keyconf, idname, 0, 0); + km->flag |= KEYMAP_MODAL; + km->modal_items= items; return km; } -wmKeyMap *WM_modalkeymap_get(wmWindowManager *wm, const char *nameid) +wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, char *idname) { wmKeyMap *km; - for(km= wm->keymaps.first; km; km= km->next) - if(km->is_modal) - if(0==strncmp(nameid, km->nameid, KMAP_MAX_NAME)) + for(km= keyconf->keymaps.first; km; km= km->next) + if(km->flag & KEYMAP_MODAL) + if(0==strncmp(idname, km->idname, KMAP_MAX_NAME)) break; return km; } -void WM_modalkeymap_add_item(wmKeyMap *km, short type, short val, int modifier, short keymodifier, short value) +void WM_modalkeymap_add_item(wmKeyMap *km, int type, int val, int modifier, int keymodifier, int value) { - wmKeymapItem *kmi= MEM_callocN(sizeof(wmKeymapItem), "keymap entry"); + wmKeyMapItem *kmi= MEM_callocN(sizeof(wmKeyMapItem), "keymap entry"); - BLI_addtail(&km->keymap, kmi); + BLI_addtail(&km->items, kmi); kmi->propvalue= value; keymap_event_set(kmi, type, val, modifier, keymodifier); } -void WM_modalkeymap_assign(wmKeyMap *km, const char *opname) +void WM_modalkeymap_assign(wmKeyMap *km, char *opname) { wmOperatorType *ot= WM_operatortype_find(opname, 0); @@ -200,7 +288,6 @@ void WM_modalkeymap_assign(wmKeyMap *km, const char *opname) printf("error: modalkeymap_assign, unknown operator %s\n", opname); } - /* ***************** get string from key events **************** */ const char *WM_key_event_string(short type) @@ -212,9 +299,9 @@ const char *WM_key_event_string(short type) return ""; } -static char *wm_keymap_item_to_string(wmKeymapItem *kmi, char *str, int len) +char *WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, int len) { - char buf[100]; + char buf[128]; buf[0]= 0; @@ -236,25 +323,30 @@ static char *wm_keymap_item_to_string(wmKeymapItem *kmi, char *str, int len) return str; } -static wmKeymapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *handlers, const char *opname, int opcontext, IDProperty *properties, int compare_props) +static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *handlers, const char *opname, int opcontext, IDProperty *properties, int compare_props, wmKeyMap **keymap_r) { + wmWindowManager *wm= CTX_wm_manager(C); wmEventHandler *handler; wmKeyMap *keymap; - wmKeymapItem *kmi; + wmKeyMapItem *kmi; /* find keymap item in handlers */ for(handler=handlers->first; handler; handler=handler->next) { - keymap= handler->keymap; + keymap= WM_keymap_active(wm, handler->keymap); if(keymap && (!keymap->poll || keymap->poll((bContext*)C))) { - for(kmi=keymap->keymap.first; kmi; kmi=kmi->next) { + for(kmi=keymap->items.first; kmi; kmi=kmi->next) { if(strcmp(kmi->idname, opname) == 0 && WM_key_event_string(kmi->type)[0]) { if(compare_props) { - if(kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data)) + if(kmi->ptr && IDP_EqualsProperties(properties, kmi->ptr->data)) { + if(keymap_r) *keymap_r= keymap; return kmi; + } } - else + else { + if(keymap_r) *keymap_r= keymap; return kmi; + } } } } @@ -263,74 +355,162 @@ static wmKeymapItem *wm_keymap_item_find_handlers(const bContext *C, ListBase *h return NULL; } -static wmKeymapItem *wm_keymap_item_find(const bContext *C, const char *opname, int opcontext, IDProperty *properties, int compare_props) +static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, const char *opname, int opcontext, IDProperty *properties, int compare_props, wmKeyMap **keymap_r) { - wmKeymapItem *found= NULL; + wmWindow *win= CTX_wm_window(C); + ScrArea *sa= CTX_wm_area(C); + ARegion *ar= CTX_wm_region(C); + wmKeyMapItem *found= NULL; /* look into multiple handler lists to find the item */ - if(CTX_wm_window(C)) - found= wm_keymap_item_find_handlers(C, &CTX_wm_window(C)->handlers, opname, opcontext, properties, compare_props); + if(win) + found= wm_keymap_item_find_handlers(C, &win->handlers, opname, opcontext, properties, compare_props, keymap_r); - if(CTX_wm_area(C) && found==NULL) - found= wm_keymap_item_find_handlers(C, &CTX_wm_area(C)->handlers, opname, opcontext, properties, compare_props); + if(sa && found==NULL) + found= wm_keymap_item_find_handlers(C, &sa->handlers, opname, opcontext, properties, compare_props, keymap_r); if(found==NULL) { if(ELEM(opcontext, WM_OP_EXEC_REGION_WIN, WM_OP_INVOKE_REGION_WIN)) { - if(CTX_wm_area(C)) { - ARegion *ar= CTX_wm_area(C)->regionbase.first; + if(sa) { + ARegion *ar= sa->regionbase.first; for(; ar; ar= ar->next) if(ar->regiontype==RGN_TYPE_WINDOW) break; if(ar) - found= wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props); + found= wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, keymap_r); } } else { - if(CTX_wm_region(C)) - found= wm_keymap_item_find_handlers(C, &CTX_wm_region(C)->handlers, opname, opcontext, properties, compare_props); + if(ar) + found= wm_keymap_item_find_handlers(C, &ar->handlers, opname, opcontext, properties, compare_props, keymap_r); } } return found; } -char *WM_key_event_operator_string(const bContext *C, const char *opname, int opcontext, IDProperty *properties, char *str, int len) +static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const char *opname, int opcontext, IDProperty *properties, wmKeyMap **keymap_r) { - wmKeymapItem *found= wm_keymap_item_find(C, opname, opcontext, properties, 1); + wmKeyMapItem *found= wm_keymap_item_find_props(C, opname, opcontext, properties, 1, keymap_r); if(!found) - found= wm_keymap_item_find(C, opname, opcontext, properties, 0); + found= wm_keymap_item_find_props(C, opname, opcontext, properties, 0, keymap_r); + + return found; +} + +char *WM_key_event_operator_string(const bContext *C, const char *opname, int opcontext, IDProperty *properties, char *str, int len) +{ + wmKeyMapItem *kmi= wm_keymap_item_find(C, opname, opcontext, properties, NULL); - if(found) { - wm_keymap_item_to_string(found, str, len); + if(kmi) { + WM_keymap_item_to_string(kmi, str, len); return str; } return NULL; } -/* searches context and changes keymap item, if found */ -void WM_key_event_operator_change(const bContext *C, const char *opname, int opcontext, IDProperty *properties, short key, short modifier) +/* ***************** user preferences ******************* */ + +wmKeyMap *WM_keymap_active(wmWindowManager *wm, wmKeyMap *keymap) { - wmKeymapItem *found= wm_keymap_item_find(C, opname, opcontext, properties, 1); + wmKeyConfig *keyconf; + wmKeyMap *km; - if(!found) - found= wm_keymap_item_find(C, opname, opcontext, properties, 0); + if(!keymap) + return NULL; + + /* first user defined keymaps */ + km= wm_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid); + if(km) + return km; + + /* then user key config */ + keyconf= wm_keyconfig_list_find(&wm->keyconfigs, U.keyconfigstr); + if(keyconf) { + km= wm_keymap_list_find(&keyconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid); + if(km) + return km; + } - if(found) { - keymap_event_set(found, key, KM_PRESS, modifier, 0); + /* then use default */ + km= wm_keymap_list_find(&wm->defaultconf->keymaps, keymap->idname, keymap->spaceid, keymap->regionid); + return km; +} + +wmKeyMap *WM_keymap_copy_to_user(wmKeyMap *keymap) +{ + wmKeyMap *usermap; + wmKeyMapItem *kmi; + + usermap= wm_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid); + + if(!usermap) { + /* not saved yet, duplicate existing */ + usermap= MEM_dupallocN(keymap); + usermap->modal_items= NULL; + usermap->poll= NULL; + usermap->flag |= KEYMAP_USER; + + BLI_addtail(&U.keymaps, usermap); + } + else { + /* already saved, free items for re-copy */ + WM_keymap_free(usermap); + } + + BLI_duplicatelist(&usermap->items, &keymap->items); + + for(kmi=usermap->items.first; kmi; kmi=kmi->next) { + if(kmi->properties) { + kmi->ptr= MEM_callocN(sizeof(PointerRNA), "UserKeyMapItemPtr"); + WM_operator_properties_create(kmi->ptr, kmi->idname); + + kmi->properties= IDP_CopyProperty(kmi->properties); + kmi->ptr->data= kmi->properties; + } + } + + for(kmi=keymap->items.first; kmi; kmi=kmi->next) + kmi->flag &= ~KMI_EXPANDED; + + return usermap; +} + +void WM_keymap_restore_to_default(wmKeyMap *keymap) +{ + wmKeyMap *usermap; + + usermap= wm_keymap_list_find(&U.keymaps, keymap->idname, keymap->spaceid, keymap->regionid); + + if(usermap) { + WM_keymap_free(usermap); + BLI_freelinkN(&U.keymaps, usermap); } } -/* ********************* */ - -int WM_key_event_is_tweak(short type) +/* searches context and changes keymap item, if found */ +void WM_key_event_operator_change(const bContext *C, const char *opname, int opcontext, IDProperty *properties, short key, short modifier) { - if(type>=EVT_TWEAK_L && type<=EVT_GESTURE) - return 1; - return 0; + wmWindowManager *wm= CTX_wm_manager(C); + wmKeyMap *keymap; + wmKeyMapItem *kmi; + + kmi= wm_keymap_item_find(C, opname, opcontext, properties, &keymap); + + if(kmi) { + /* if the existing one is in a default keymap, copy it + to user preferences, and lookup again so we get a + key map item from the user preferences we can modify */ + if(BLI_findindex(&wm->defaultconf->keymaps, keymap) >= 0) { + WM_keymap_copy_to_user(keymap); + kmi= wm_keymap_item_find(C, opname, opcontext, properties, NULL); + } + + keymap_event_set(kmi, key, KM_PRESS, modifier, 0); + } } - diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 9ec0ce0df8d..a92fcee48e2 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -517,22 +517,33 @@ int WM_operator_filesel(bContext *C, wmOperator *op, wmEvent *event) /* default properties for fileselect */ void WM_operator_properties_filesel(wmOperatorType *ot, int filter, short type) { - RNA_def_string_file_path(ot->srna, "path", "", FILE_MAX, "FilePath", "Path to file."); - RNA_def_string_file_name(ot->srna, "filename", "", FILE_MAX, "FileName", "Name of the file."); + PropertyRNA *prop; + + RNA_def_string_file_path(ot->srna, "path", "", FILE_MAX, "File Path", "Path to file."); + RNA_def_string_file_name(ot->srna, "filename", "", FILE_MAX, "File Name", "Name of the file."); RNA_def_string_dir_path(ot->srna, "directory", "", FILE_MAX, "Directory", "Directory of the file."); - RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE), "Filter .blend files", ""); - RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE), "Filter image files", ""); - RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE), "Filter movie files", ""); - RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE), "Filter python files", ""); - RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE), "Filter font files", ""); - RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE), "Filter sound files", ""); - RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE), "Filter text files", ""); - RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE), "Filter folders", ""); + prop= RNA_def_boolean(ot->srna, "filter_blender", (filter & BLENDERFILE), "Filter .blend files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_image", (filter & IMAGEFILE), "Filter image files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_movie", (filter & MOVIEFILE), "Filter movie files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_python", (filter & PYSCRIPTFILE), "Filter python files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_font", (filter & FTFONTFILE), "Filter font files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_sound", (filter & SOUNDFILE), "Filter sound files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_text", (filter & TEXTFILE), "Filter text files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); + prop= RNA_def_boolean(ot->srna, "filter_folder", (filter & FOLDERFILE), "Filter folders", ""); + RNA_def_property_flag(prop, PROP_HIDDEN); - RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, + prop= RNA_def_int(ot->srna, "filemode", type, FILE_LOADLIB, FILE_SPECIAL, "File Browser Mode", "The setting for the file browser mode to load a .blend file, a library or a special file.", FILE_LOADLIB, FILE_SPECIAL); + RNA_def_property_flag(prop, PROP_HIDDEN); } /* op->poll */ @@ -1103,6 +1114,8 @@ static void WM_OT_link_append(wmOperatorType *ot) ot->exec= wm_link_append_exec; ot->poll= WM_operator_winactive; + ot->flag |= OPTYPE_UNDO; + WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_LOADLIB); RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending."); @@ -1382,7 +1395,7 @@ static void wm_gesture_end(bContext *C, wmOperator *op) int WM_border_select_invoke(bContext *C, wmOperator *op, wmEvent *event) { - if(WM_key_event_is_tweak(event->type)) + if(ISTWEAK(event->type)) op->customdata= WM_gesture_new(C, event, WM_GESTURE_RECT); else op->customdata= WM_gesture_new(C, event, WM_GESTURE_CROSS_RECT); @@ -2146,9 +2159,9 @@ void wm_operatortype_init(void) } /* default keymap for windows and screens, only call once per WM */ -void wm_window_keymap(wmWindowManager *wm) +void wm_window_keymap(wmKeyConfig *keyconf) { - wmKeyMap *keymap= WM_keymap_find(wm, "Window", 0, 0); + wmKeyMap *keymap= WM_keymap_find(keyconf, "Window", 0, 0); /* items to make WM work */ WM_keymap_verify_item(keymap, "WM_OT_jobs_timer", TIMERJOBS, KM_ANY, KM_ANY, 0); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index e3cfb9ad60d..44b7b60e451 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -373,15 +373,15 @@ void wm_window_add_ghostwindows(wmWindowManager *wm) /* happens after fileread */ if(win->eventstate==NULL) win->eventstate= MEM_callocN(sizeof(wmEvent), "window event state"); - + /* add keymap handlers (1 handler for all keys in map!) */ - keymap= WM_keymap_find(wm, "Window", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Window", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); - keymap= WM_keymap_find(wm, "Screen", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Screen", 0, 0); WM_event_add_keymap_handler(&win->handlers, keymap); - keymap= WM_keymap_find(wm, "Screen Editing", 0, 0); + keymap= WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0); WM_event_add_keymap_handler(&win->modalhandlers, keymap); wm_window_title(wm, win); diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index a7529157072..832558b961f 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -54,7 +54,7 @@ extern void wm_report_free(wmReport *report); /* wm_operator.c, for init/exit */ void wm_operatortype_free(void); void wm_operatortype_init(void); -void wm_window_keymap(wmWindowManager *wm); +void wm_window_keymap(wmKeyConfig *keyconf); void wm_tweakevent_test(bContext *C, wmEvent *event, int action); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 4360e49e371..4322f70ea61 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -44,7 +44,6 @@ typedef struct wmEventHandler { /* keymap handler */ wmKeyMap *keymap; /* pointer to builtin/custom keymaps */ - rcti *bblocal, *bbwin; /* optional local and windowspace bb */ /* modal operator handler */ diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index cc6041ce529..b33c4bd14e8 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -199,9 +199,17 @@ /* test wether the event is a key on the keyboard */ #define ISKEYBOARD(event) (event >=' ' && event <=320) -/* test whether event type is acceptable as hotkey, excluding modifiers */ -#define ISHOTKEY(event) (ISKEYBOARD(event) && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY)) + /* test wether the event is a mouse button */ +#define ISMOUSE(event) (event >= LEFTMOUSE && event <= WHEELOUTMOUSE) + /* test wether the event is timer event */ +#define ISTIMER(event) (event >= TIMER && event <= TIMERJOBS) + + /* test wether the event is tweak event */ +#define ISTWEAK(event) (event >= EVT_TWEAK_L && event <= EVT_GESTURE) + +/* test whether event type is acceptable as hotkey, excluding modifiers */ +#define ISHOTKEY(event) ((ISKEYBOARD(event) || ISMOUSE(event)) && !(event>=LEFTCTRLKEY && event<=ESCKEY) && !(event>=UNKNOWNKEY && event<=GRLESSKEY)) /* **************** BLENDER GESTURE EVENTS ********************* */ From 5c867406aa66a1d89260c233a6bbc1a2a7912dbe Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 19:06:32 +0000 Subject: [PATCH 044/138] menus are now global (like operators), so for eg, the info add menu and the 3D add menu can be shared. --- release/scripts/ui/space_buttons.py | 1 - release/scripts/ui/space_console.py | 2 - release/scripts/ui/space_image.py | 8 --- release/scripts/ui/space_info.py | 8 --- release/scripts/ui/space_node.py | 3 -- release/scripts/ui/space_outliner.py | 1 - release/scripts/ui/space_sequencer.py | 6 --- release/scripts/ui/space_text.py | 7 --- release/scripts/ui/space_time.py | 4 -- release/scripts/ui/space_userpref.py | 1 - release/scripts/ui/space_view3d.py | 50 ------------------- source/blender/blenkernel/BKE_screen.h | 6 +-- source/blender/blenkernel/intern/screen.c | 27 ---------- source/blender/editors/include/UI_interface.h | 2 +- .../editors/interface/interface_layout.c | 2 +- .../editors/interface/interface_regions.c | 4 +- source/blender/editors/mesh/editmesh_mods.c | 2 +- source/blender/editors/object/object_add.c | 45 ----------------- source/blender/editors/object/object_intern.h | 1 - source/blender/editors/object/object_ops.c | 5 +- .../blender/editors/space_node/node_header.c | 2 +- source/blender/makesrna/intern/rna_ui.c | 17 ++----- source/blender/python/intern/bpy_operator.c | 2 +- source/blender/windowmanager/WM_api.h | 7 +++ source/blender/windowmanager/intern/wm.c | 46 +++++++++++++++++ .../windowmanager/intern/wm_init_exit.c | 1 + .../windowmanager/intern/wm_operators.c | 2 +- .../blender/windowmanager/intern/wm_window.c | 1 - source/blender/windowmanager/wm_window.h | 1 - 29 files changed, 70 insertions(+), 194 deletions(-) diff --git a/release/scripts/ui/space_buttons.py b/release/scripts/ui/space_buttons.py index aa89c06ea08..299e8bc9dae 100644 --- a/release/scripts/ui/space_buttons.py +++ b/release/scripts/ui/space_buttons.py @@ -22,7 +22,6 @@ class Buttons_HT_header(bpy.types.Header): row.itemR(scene, "current_frame") class Buttons_MT_view(bpy.types.Menu): - __space_type__ = 'PROPERTIES' __label__ = "View" def draw(self, context): diff --git a/release/scripts/ui/space_console.py b/release/scripts/ui/space_console.py index a65d7577c7a..5bb211f7d98 100644 --- a/release/scripts/ui/space_console.py +++ b/release/scripts/ui/space_console.py @@ -38,7 +38,6 @@ class CONSOLE_HT_header(bpy.types.Header): row.itemO("console.autocomplete", text="Autocomplete") class CONSOLE_MT_console(bpy.types.Menu): - __space_type__ = 'CONSOLE' __label__ = "Console" def draw(self, context): @@ -51,7 +50,6 @@ class CONSOLE_MT_console(bpy.types.Menu): layout.itemO("console.paste") class CONSOLE_MT_report(bpy.types.Menu): - __space_type__ = 'CONSOLE' __label__ = "Report" def draw(self, context): diff --git a/release/scripts/ui/space_image.py b/release/scripts/ui/space_image.py index b14bec0e40e..c1a4fc723ca 100644 --- a/release/scripts/ui/space_image.py +++ b/release/scripts/ui/space_image.py @@ -2,7 +2,6 @@ import bpy class IMAGE_MT_view(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "View" def draw(self, context): @@ -44,7 +43,6 @@ class IMAGE_MT_view(bpy.types.Menu): layout.itemO("screen.screen_full_area") class IMAGE_MT_select(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "Select" def draw(self, context): @@ -65,7 +63,6 @@ class IMAGE_MT_select(bpy.types.Menu): layout.itemO("uv.select_linked") class IMAGE_MT_image(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "Image" def draw(self, context): @@ -109,7 +106,6 @@ class IMAGE_MT_image(bpy.types.Menu): layout.itemR(sima, "image_painting") class IMAGE_MT_uvs_showhide(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "Show/Hide Faces" def draw(self, context): @@ -120,7 +116,6 @@ class IMAGE_MT_uvs_showhide(bpy.types.Menu): layout.item_booleanO("uv.hide", "unselected", True) class IMAGE_MT_uvs_transform(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "Transform" def draw(self, context): @@ -131,7 +126,6 @@ class IMAGE_MT_uvs_transform(bpy.types.Menu): layout.itemO("tfm.resize") class IMAGE_MT_uvs_mirror(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "Mirror" def draw(self, context): @@ -145,7 +139,6 @@ class IMAGE_MT_uvs_mirror(bpy.types.Menu): props.constraint_axis[1]= True class IMAGE_MT_uvs_weldalign(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "Weld/Align" def draw(self, context): @@ -155,7 +148,6 @@ class IMAGE_MT_uvs_weldalign(bpy.types.Menu): layout.items_enumO("uv.align", "axis") # W, 2/3/4 class IMAGE_MT_uvs(bpy.types.Menu): - __space_type__ = 'IMAGE_EDITOR' __label__ = "UVs" def draw(self, context): diff --git a/release/scripts/ui/space_info.py b/release/scripts/ui/space_info.py index 3805a7d0dec..32068f1b941 100644 --- a/release/scripts/ui/space_info.py +++ b/release/scripts/ui/space_info.py @@ -38,7 +38,6 @@ class INFO_HT_header(bpy.types.Header): layout.itemL(text=scene.statistics()) class INFO_MT_file(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "File" def draw(self, context): @@ -78,7 +77,6 @@ class INFO_MT_file(bpy.types.Menu): layout.itemO("wm.exit_blender", text="Quit") class INFO_MT_file_import(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "Import" def draw(self, context): @@ -89,7 +87,6 @@ class INFO_MT_file_import(bpy.types.Menu): class INFO_MT_file_export(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "Export" def draw(self, context): @@ -104,7 +101,6 @@ class INFO_MT_file_export(bpy.types.Menu): class INFO_MT_file_external_data(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "External Data" def draw(self, context): @@ -121,7 +117,6 @@ class INFO_MT_file_external_data(bpy.types.Menu): layout.itemO("file.find_missing_files") class INFO_MT_add(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "Add" def draw(self, context): @@ -151,7 +146,6 @@ class INFO_MT_add(bpy.types.Menu): layout.item_menu_enumO("object.effector_add", "type", 'EMPTY', text="Force Field", icon='ICON_OUTLINER_OB_EMPTY') class INFO_MT_game(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "Game" def draw(self, context): @@ -169,7 +163,6 @@ class INFO_MT_game(bpy.types.Menu): layout.itemR(gs, "deprecation_warnings") class INFO_MT_render(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "Render" def draw(self, context): @@ -185,7 +178,6 @@ class INFO_MT_render(bpy.types.Menu): layout.itemO("screen.render_view_show") class INFO_MT_help(bpy.types.Menu): - __space_type__ = 'INFO' __label__ = "Help" def draw(self, context): diff --git a/release/scripts/ui/space_node.py b/release/scripts/ui/space_node.py index b32e6a9f61a..5c5c49afbc7 100644 --- a/release/scripts/ui/space_node.py +++ b/release/scripts/ui/space_node.py @@ -48,7 +48,6 @@ class NODE_HT_header(bpy.types.Header): layout.itemR(snode, "backdrop") class NODE_MT_view(bpy.types.Menu): - __space_type__ = 'NODE_EDITOR' __label__ = "View" def draw(self, context): @@ -66,7 +65,6 @@ class NODE_MT_view(bpy.types.Menu): layout.itemO("screen.screen_full_area") class NODE_MT_select(bpy.types.Menu): - __space_type__ = 'NODE_EDITOR' __label__ = "Select" def draw(self, context): @@ -80,7 +78,6 @@ class NODE_MT_select(bpy.types.Menu): layout.itemO("node.select_linked_to") class NODE_MT_node(bpy.types.Menu): - __space_type__ = 'NODE_EDITOR' __label__ = "Node" def draw(self, context): diff --git a/release/scripts/ui/space_outliner.py b/release/scripts/ui/space_outliner.py index 522b620e29d..f3c45983d76 100644 --- a/release/scripts/ui/space_outliner.py +++ b/release/scripts/ui/space_outliner.py @@ -36,7 +36,6 @@ class OUTLINER_HT_header(bpy.types.Header): class OUTLINER_MT_view(bpy.types.Menu): - __space_type__ = 'OUTLINER' __label__ = "View" def draw(self, context): diff --git a/release/scripts/ui/space_sequencer.py b/release/scripts/ui/space_sequencer.py index a804998cdaa..582481401a6 100644 --- a/release/scripts/ui/space_sequencer.py +++ b/release/scripts/ui/space_sequencer.py @@ -38,7 +38,6 @@ class SEQUENCER_HT_header(bpy.types.Header): layout.itemR(st, "display_channel", text="Channel") class SEQUENCER_MT_view(bpy.types.Menu): - __space_type__ = 'SEQUENCE_EDITOR' __label__ = "View" def draw(self, context): @@ -106,7 +105,6 @@ class SEQUENCER_MT_view(bpy.types.Menu): """ class SEQUENCER_MT_select(bpy.types.Menu): - __space_type__ = 'SEQUENCE_EDITOR' __label__ = "Select" def draw(self, context): @@ -127,7 +125,6 @@ class SEQUENCER_MT_select(bpy.types.Menu): layout.itemO("sequencer.select_inverse") class SEQUENCER_MT_marker(bpy.types.Menu): - __space_type__ = 'SEQUENCE_EDITOR' __label__ = "Marker (TODO)" def draw(self, context): @@ -146,7 +143,6 @@ class SEQUENCER_MT_marker(bpy.types.Menu): #layout.itemO("sequencer.sound_strip_add", text="Transform Markers") # toggle, will be rna - (sseq->flag & SEQ_MARKER_TRANS) class SEQUENCER_MT_add(bpy.types.Menu): - __space_type__ = 'SEQUENCE_EDITOR' __label__ = "Add" def draw(self, context): @@ -163,7 +159,6 @@ class SEQUENCER_MT_add(bpy.types.Menu): layout.itemM("SEQUENCER_MT_add_effect") class SEQUENCER_MT_add_effect(bpy.types.Menu): - __space_type__ = 'SEQUENCE_EDITOR' __label__ = "Effect Strip..." def draw(self, context): @@ -187,7 +182,6 @@ class SEQUENCER_MT_add_effect(bpy.types.Menu): layout.item_enumO("sequencer.effect_strip_add", 'type', 'SPEED') class SEQUENCER_MT_strip(bpy.types.Menu): - __space_type__ = 'SEQUENCE_EDITOR' __label__ = "Strip" def draw(self, context): diff --git a/release/scripts/ui/space_text.py b/release/scripts/ui/space_text.py index 117033c50a1..4860767d69d 100644 --- a/release/scripts/ui/space_text.py +++ b/release/scripts/ui/space_text.py @@ -98,7 +98,6 @@ class TEXT_PT_find(bpy.types.Panel): row.itemR(st, "find_all", text="All") class TEXT_MT_text(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "Text" def draw(self, context): @@ -140,7 +139,6 @@ class TEXT_MT_text(bpy.types.Menu): #endif class TEXT_MT_edit_view(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "View" def draw(self, context): @@ -150,7 +148,6 @@ class TEXT_MT_edit_view(bpy.types.Menu): layout.item_enumO("text.move", "type", 'FILE_BOTTOM', text="Bottom of File") class TEXT_MT_edit_select(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "Select" def draw(self, context): @@ -160,7 +157,6 @@ class TEXT_MT_edit_select(bpy.types.Menu): layout.itemO("text.select_line") class TEXT_MT_edit_markers(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "Markers" def draw(self, context): @@ -171,7 +167,6 @@ class TEXT_MT_edit_markers(bpy.types.Menu): layout.itemO("text.previous_marker") class TEXT_MT_format(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "Format" def draw(self, context): @@ -190,7 +185,6 @@ class TEXT_MT_format(bpy.types.Menu): layout.item_menu_enumO("text.convert_whitespace", "type") class TEXT_MT_edit_to3d(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "Text To 3D Object" def draw(self, context): @@ -200,7 +194,6 @@ class TEXT_MT_edit_to3d(bpy.types.Menu): layout.item_booleanO("text.to_3d_object", "split_lines", True, text="One Object Per Line"); class TEXT_MT_edit(bpy.types.Menu): - __space_type__ = 'TEXT_EDITOR' __label__ = "Edit" def poll(self, context): diff --git a/release/scripts/ui/space_time.py b/release/scripts/ui/space_time.py index fdb01d5c216..2ead4305960 100644 --- a/release/scripts/ui/space_time.py +++ b/release/scripts/ui/space_time.py @@ -64,7 +64,6 @@ class TIME_HT_header(bpy.types.Header): row.itemO("anim.delete_keyframe", text="", icon='ICON_KEY_DEHLT') class TIME_MT_view(bpy.types.Menu): - __space_type__ = 'TIMELINE' __label__ = "View" def draw(self, context): @@ -79,7 +78,6 @@ class TIME_MT_view(bpy.types.Menu): layout.itemR(st, "only_selected") class TIME_MT_frame(bpy.types.Menu): - __space_type__ = 'TIMELINE' __label__ = "Frame" def draw(self, context): @@ -104,7 +102,6 @@ class TIME_MT_frame(bpy.types.Menu): sub.itemM("TIME_MT_autokey") class TIME_MT_playback(bpy.types.Menu): - __space_type__ = 'TIMELINE' __label__ = "Playback" def draw(self, context): @@ -132,7 +129,6 @@ class TIME_MT_playback(bpy.types.Menu): layout.itemR(scene, "scrub_audio") class TIME_MT_autokey(bpy.types.Menu): - __space_type__ = 'TIMELINE' __label__ = "Auto-Keyframing Mode" def draw(self, context): diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index ff4461db02f..27c826b133b 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -18,7 +18,6 @@ class USERPREF_HT_header(bpy.types.Header): layout.itemO("wm.keyconfig_save", "Save Key Configuration...") class USERPREF_MT_view(bpy.types.Menu): - __space_type__ = 'USER_PREFERENCES' __label__ = "View" def draw(self, context): diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index ef1947dbb39..ecc4d298b94 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -44,7 +44,6 @@ class VIEW3D_HT_header(bpy.types.Header): # ********** Utilities ********** class VIEW3D_MT_showhide(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Show/Hide" _operator_name = "" @@ -56,7 +55,6 @@ class VIEW3D_MT_showhide(bpy.types.Menu): layout.item_booleanO("%s.hide" % self._operator_name, "unselected", True, text="Hide Unselected") class VIEW3D_MT_snap(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Snap" def draw(self, context): @@ -75,7 +73,6 @@ class VIEW3D_MT_snap(bpy.types.Menu): # ********** View menus ********** class VIEW3D_MT_view(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "View" def draw(self, context): @@ -120,7 +117,6 @@ class VIEW3D_MT_view(bpy.types.Menu): layout.itemO("screen.screen_full_area", text="Toggle Full Screen") class VIEW3D_MT_view_navigation(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Navigation" def draw(self, context): @@ -142,7 +138,6 @@ class VIEW3D_MT_view_navigation(bpy.types.Menu): layout.itemO("view3d.fly") class VIEW3D_MT_view_align(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Align View" def draw(self, context): @@ -151,7 +146,6 @@ class VIEW3D_MT_view_align(bpy.types.Menu): layout.itemO("view3d.view_center") class VIEW3D_MT_view_cameras(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Cameras" def draw(self, context): @@ -162,7 +156,6 @@ class VIEW3D_MT_view_cameras(bpy.types.Menu): # ********** Select menus, suffix from context.mode ********** class VIEW3D_MT_select_object(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -182,7 +175,6 @@ class VIEW3D_MT_select_object(bpy.types.Menu): layout.itemO("object.select_pattern", text="Select Pattern...") class VIEW3D_MT_select_pose(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -213,7 +205,6 @@ class VIEW3D_MT_select_pose(bpy.types.Menu): props.direction = 'CHILD' class VIEW3D_MT_select_particle(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -232,7 +223,6 @@ class VIEW3D_MT_select_particle(bpy.types.Menu): layout.itemO("particle.select_less") class VIEW3D_MT_select_edit_mesh(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -276,7 +266,6 @@ class VIEW3D_MT_select_edit_mesh(bpy.types.Menu): layout.itemO("mesh.region_to_loop") class VIEW3D_MT_select_edit_curve(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -305,7 +294,6 @@ class VIEW3D_MT_select_edit_curve(bpy.types.Menu): layout.itemO("curve.select_less") class VIEW3D_MT_select_edit_surface(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -331,7 +319,6 @@ class VIEW3D_MT_select_edit_surface(bpy.types.Menu): layout.itemO("curve.select_less") class VIEW3D_MT_select_edit_metaball(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -349,7 +336,6 @@ class VIEW3D_MT_select_edit_metaball(bpy.types.Menu): layout.itemO("mball.select_random_metaelems") class VIEW3D_MT_select_edit_lattice(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -362,7 +348,6 @@ class VIEW3D_MT_select_edit_lattice(bpy.types.Menu): layout.itemO("lattice.select_all_toggle", text="Select/Deselect All") class VIEW3D_MT_select_edit_armature(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -391,7 +376,6 @@ class VIEW3D_MT_select_edit_armature(bpy.types.Menu): props.direction = 'CHILD' class VIEW3D_MT_select_face(bpy.types.Menu):# XXX no matching enum - __space_type__ = 'VIEW_3D' __label__ = "Select" def draw(self, context): @@ -402,7 +386,6 @@ class VIEW3D_MT_select_face(bpy.types.Menu):# XXX no matching enum # ********** Object menu ********** class VIEW3D_MT_object(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __context__ = "objectmode" __label__ = "Object" @@ -440,7 +423,6 @@ class VIEW3D_MT_object(bpy.types.Menu): layout.itemM("VIEW3D_MT_object_showhide") class VIEW3D_MT_object_clear(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Clear" def draw(self, context): @@ -452,7 +434,6 @@ class VIEW3D_MT_object_clear(bpy.types.Menu): layout.itemO("object.origin_clear", text="Origin") class VIEW3D_MT_object_parent(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Parent" def draw(self, context): @@ -462,7 +443,6 @@ class VIEW3D_MT_object_parent(bpy.types.Menu): layout.itemO("object.parent_clear", text="Clear") class VIEW3D_MT_object_track(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Track" def draw(self, context): @@ -472,7 +452,6 @@ class VIEW3D_MT_object_track(bpy.types.Menu): layout.itemO("object.track_clear", text="Clear") class VIEW3D_MT_object_group(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Group" def draw(self, context): @@ -487,7 +466,6 @@ class VIEW3D_MT_object_group(bpy.types.Menu): layout.itemO("group.objects_remove_active") class VIEW3D_MT_object_constraints(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Constraints" def draw(self, context): @@ -497,7 +475,6 @@ class VIEW3D_MT_object_constraints(bpy.types.Menu): layout.itemO("object.constraints_clear") class VIEW3D_MT_object_showhide(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Show/Hide" def draw(self, context): @@ -510,7 +487,6 @@ class VIEW3D_MT_object_showhide(bpy.types.Menu): # ********** Vertex paint menu ********** class VIEW3D_MT_paint_vertex(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Paint" def draw(self, context): @@ -525,7 +501,6 @@ class VIEW3D_MT_paint_vertex(bpy.types.Menu): # ********** Sculpt menu ********** class VIEW3D_MT_sculpt(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Sculpt" def draw(self, context): @@ -561,7 +536,6 @@ class VIEW3D_MT_sculpt(bpy.types.Menu): # ********** Particle menu ********** class VIEW3D_MT_particle(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Particle" def draw(self, context): @@ -591,7 +565,6 @@ class VIEW3D_MT_particle_showhide(VIEW3D_MT_showhide): # ********** Pose Menu ********** class VIEW3D_MT_pose(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Pose" def draw(self, context): @@ -651,7 +624,6 @@ class VIEW3D_MT_pose(bpy.types.Menu): layout.item_menu_enumO("pose.flags_set", 'mode', text="Bone Settings") class VIEW3D_MT_pose_transform(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Clear Transform" def draw(self, context): @@ -666,7 +638,6 @@ class VIEW3D_MT_pose_transform(bpy.types.Menu): layout.itemL(text="Origin") class VIEW3D_MT_pose_pose(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Pose Library" def draw(self, context): @@ -681,7 +652,6 @@ class VIEW3D_MT_pose_pose(bpy.types.Menu): layout.itemO("poselib.pose_remove", text="Remove Pose...") class VIEW3D_MT_pose_motion(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Motion Paths" def draw(self, context): @@ -691,7 +661,6 @@ class VIEW3D_MT_pose_motion(bpy.types.Menu): layout.itemO("pose.paths_clear", text="Clear") class VIEW3D_MT_pose_group(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Bone Groups" def draw(self, context): @@ -706,7 +675,6 @@ class VIEW3D_MT_pose_group(bpy.types.Menu): class VIEW3D_MT_pose_ik(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Inverse Kinematics" def draw(self, context): @@ -716,7 +684,6 @@ class VIEW3D_MT_pose_ik(bpy.types.Menu): layout.itemO("pose.ik_clear") class VIEW3D_MT_pose_constraints(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Constraints" def draw(self, context): @@ -732,7 +699,6 @@ class VIEW3D_MT_pose_showhide(VIEW3D_MT_showhide): # Edit MESH class VIEW3D_MT_edit_mesh(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Mesh" def draw(self, context): @@ -775,7 +741,6 @@ class VIEW3D_MT_edit_mesh(bpy.types.Menu): layout.itemM("VIEW3D_MT_edit_mesh_showhide") class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Vertices" def draw(self, context): @@ -792,7 +757,6 @@ class VIEW3D_MT_edit_mesh_vertices(bpy.types.Menu): layout.itemO("mesh.remove_doubles") class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Edges" def draw(self, context): @@ -817,7 +781,6 @@ class VIEW3D_MT_edit_mesh_edges(bpy.types.Menu): layout.item_enumO("mesh.edge_rotate", "direction", 'CCW', text="Rotate Edge CCW") class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Faces" def draw(self, context): @@ -839,7 +802,6 @@ class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu): layout.itemO("mesh.faces_shade_flat") class VIEW3D_MT_edit_mesh_normals(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Normals" def draw(self, context): @@ -889,13 +851,11 @@ def draw_curve(self, context): layout.itemM("VIEW3D_MT_edit_curve_showhide") class VIEW3D_MT_edit_curve(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Curve" draw = draw_curve class VIEW3D_MT_edit_curve_ctrlpoints(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Control Points" def draw(self, context): @@ -913,7 +873,6 @@ class VIEW3D_MT_edit_curve_ctrlpoints(bpy.types.Menu): layout.item_menu_enumO("curve.handle_type_set", "type") class VIEW3D_MT_edit_curve_segments(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Segments" def draw(self, context): @@ -927,14 +886,12 @@ class VIEW3D_MT_edit_curve_showhide(VIEW3D_MT_showhide): # Edit SURFACE class VIEW3D_MT_edit_surface(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Surface" draw = draw_curve # Edit TEXT class VIEW3D_MT_edit_text(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Text" def draw(self, context): @@ -947,7 +904,6 @@ class VIEW3D_MT_edit_text(bpy.types.Menu): layout.itemm("view3d_mt_edit_text_chars") class VIEW3D_MT_edit_text_chars(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Special Characters" def draw(self, context): @@ -982,7 +938,6 @@ class VIEW3D_MT_edit_text_chars(bpy.types.Menu): # Edit META class VIEW3D_MT_edit_meta(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Metaball" def draw(self, context): @@ -1012,7 +967,6 @@ class VIEW3D_MT_edit_meta(bpy.types.Menu): layout.itemM("VIEW3D_MT_edit_meta_showhide") class VIEW3D_MT_edit_meta_showhide(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Show/Hide" def draw(self, context): @@ -1024,7 +978,6 @@ class VIEW3D_MT_edit_meta_showhide(bpy.types.Menu): # Edit LATTICE class VIEW3D_MT_edit_lattice(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Lattice" def draw(self, context): @@ -1045,7 +998,6 @@ class VIEW3D_MT_edit_lattice(bpy.types.Menu): # Edit ARMATURE class VIEW3D_MT_edit_armature(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Armature" def draw(self, context): @@ -1102,7 +1054,6 @@ class VIEW3D_MT_edit_armature(bpy.types.Menu): layout.item_menu_enumO("armature.flags_set", "mode", text="Bone Settings") class VIEW3D_MT_edit_armature_parent(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Parent" def draw(self, context): @@ -1112,7 +1063,6 @@ class VIEW3D_MT_edit_armature_parent(bpy.types.Menu): layout.itemO("armature.parent_clear", text="Clear") class VIEW3D_MT_edit_armature_roll(bpy.types.Menu): - __space_type__ = 'VIEW_3D' __label__ = "Bone Roll" def draw(self, context): diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 7c62c8c6dd4..39a90fe3074 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -138,9 +138,6 @@ typedef struct ARegionType { /* header type definitions */ ListBase headertypes; - - /* menu type definitions */ - ListBase menutypes; /* hardcoded constraints, smaller than these values region is not visible */ int minsizex, minsizey; @@ -200,7 +197,6 @@ typedef struct MenuType { char idname[BKE_ST_MAXNAME]; /* unique name */ char label[BKE_ST_MAXNAME]; /* for button text */ - int space_type; /* verify if the menu should draw or not */ int (*poll)(const struct bContext *, struct MenuType *); @@ -223,7 +219,7 @@ const struct ListBase *BKE_spacetypes_list(void); void BKE_spacetype_register(struct SpaceType *st); void BKE_spacetypes_free(void); /* only for quitting blender */ -MenuType *BKE_spacemenu_find(const char *idname, int spacetype); +// MenuType *BKE_spacemenu_find(const char *idname, int spacetype); /* spacedata */ void BKE_spacedata_freelist(ListBase *lb); diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 3567de5df40..918a67311a0 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -70,13 +70,8 @@ static void spacetype_free(SpaceType *st) if(ht->ext.free) ht->ext.free(ht->ext.data); - for(mt= art->menutypes.first; mt; mt= mt->next) - if(mt->ext.free) - mt->ext.free(mt->ext.data); - BLI_freelistN(&art->paneltypes); BLI_freelistN(&art->headertypes); - BLI_freelistN(&art->menutypes); } BLI_freelistN(&st->regiontypes); @@ -343,25 +338,3 @@ unsigned int BKE_screen_visible_layers(bScreen *screen) return layer; } -MenuType *BKE_spacemenu_find(const char *idname, int spacetype) -{ - SpaceType *st= BKE_spacetype_from_id(spacetype); - ARegionType *art; - MenuType* mt; - - if(st==NULL) { - printf("space type %d is invalid\n", spacetype); - return NULL; - } - - if(idname==NULL) - return NULL; - - for(art= st->regiontypes.first; art; art= art->next) - for(mt=art->menutypes.first; mt; mt=mt->next) - if(strcmp(idname, mt->idname)==0) - return mt; - - return NULL; -} - diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 3c6ed1137ae..5766fcfdb1f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -257,7 +257,7 @@ void uiPupMenuSaveOver(struct bContext *C, struct wmOperator *op, char *filename void uiPupMenuNotice(struct bContext *C, char *str, ...); void uiPupMenuError(struct bContext *C, char *str, ...); void uiPupMenuReports(struct bContext *C, struct ReportList *reports); -void uiPupMenuInvoke(struct bContext *C, const char *idname, int spacetype); /* popup registered menu */ +void uiPupMenuInvoke(struct bContext *C, const char *idname); /* popup registered menu */ /* Popup Blocks * diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index eb81044852a..b0f93472240 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1232,7 +1232,7 @@ void uiItemM(uiLayout *layout, bContext *C, char *name, int icon, char *menuname { MenuType *mt; - mt= BKE_spacemenu_find(menuname, CTX_wm_area(C)->spacetype); + mt= WM_menutype_find(menuname, FALSE); if(mt==NULL) { printf("uiItemM: not found %s\n", menuname); diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index cdb62d0a4b4..c837599baf3 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -2481,12 +2481,12 @@ void uiPupMenuReports(bContext *C, ReportList *reports) BLI_dynstr_free(ds); } -void uiPupMenuInvoke(bContext *C, const char *idname, int spacetype) +void uiPupMenuInvoke(bContext *C, const char *idname) { uiPopupMenu *pup; uiLayout *layout; Menu menu; - MenuType *mt= BKE_spacemenu_find(idname, spacetype); + MenuType *mt= WM_menutype_find(idname, TRUE); if(mt==NULL) { printf("uiPupMenuInvoke: named menu \"%s\" not found\n", idname); diff --git a/source/blender/editors/mesh/editmesh_mods.c b/source/blender/editors/mesh/editmesh_mods.c index 4669f7a6741..3c3cdf25d7b 100644 --- a/source/blender/editors/mesh/editmesh_mods.c +++ b/source/blender/editors/mesh/editmesh_mods.c @@ -119,7 +119,7 @@ void EM_select_mirrored(Object *obedit, EditMesh *em) void EM_automerge(Scene *scene, Object *obedit, int update) { - Mesh *me= (Mesh*)obedit->data; /* can be NULL */ + Mesh *me= obedit ? obedit->data : NULL; /* can be NULL */ int len; if ((scene->toolsettings->automerge) && diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 780126852ed..c552a2954b7 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -686,51 +686,6 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot) RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", ""); } -static int object_primitive_add_invoke(bContext *C, wmOperator *op, wmEvent *event) -{ - uiPopupMenu *pup= uiPupMenuBegin(C, "Add Object", 0); - uiLayout *layout= uiPupMenuLayout(pup); - - uiItemMenuEnumO(layout, "Mesh", ICON_OUTLINER_OB_MESH, "OBJECT_OT_mesh_add", "type"); - uiItemMenuEnumO(layout, "Curve", ICON_OUTLINER_OB_CURVE, "OBJECT_OT_curve_add", "type"); - uiItemMenuEnumO(layout, "Surface", ICON_OUTLINER_OB_SURFACE, "OBJECT_OT_surface_add", "type"); - uiItemMenuEnumO(layout, "Metaball", ICON_OUTLINER_OB_META, "OBJECT_OT_metaball_add", "type"); - uiItemO(layout, "Text", ICON_OUTLINER_OB_FONT, "OBJECT_OT_text_add"); - uiItemS(layout); - uiItemO(layout, "Armature", ICON_OUTLINER_OB_ARMATURE, "OBJECT_OT_armature_add"); - uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_LATTICE, "OBJECT_OT_add", "type", OB_LATTICE); - uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_add", "type", OB_EMPTY); - uiItemS(layout); - uiItemEnumO(layout, NULL, ICON_OUTLINER_OB_CAMERA, "OBJECT_OT_add", "type", OB_CAMERA); - uiItemMenuEnumO(layout, "Lamp", ICON_OUTLINER_OB_LAMP, "OBJECT_OT_lamp_add", "type"); - uiItemS(layout); - uiItemMenuEnumO(layout, "Force Field", ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_effector_add", "type"); - uiItemS(layout); - uiItemMenuEnumO(layout, "Group Instance", ICON_OUTLINER_OB_EMPTY, "OBJECT_OT_group_instance_add", "type"); - - uiPupMenuEnd(C, pup); - - /* this operator is only for a menu, not used further */ - return OPERATOR_CANCELLED; -} - -/* only used as menu */ -void OBJECT_OT_primitive_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name= "Add Primitive"; - ot->description = "Add a primitive object."; - ot->idname= "OBJECT_OT_primitive_add"; - - /* api callbacks */ - ot->invoke= object_primitive_add_invoke; - - ot->poll= ED_operator_scene_editable; - - /* flags */ - ot->flag= 0; -} - /* add dupligroup */ static EnumPropertyItem *add_dupligroup_itemf(bContext *C, PointerRNA *ptr, int *free) { diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 1a7d3841aaa..353622526d3 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -90,7 +90,6 @@ void OBJECT_OT_metaball_add(struct wmOperatorType *ot); void OBJECT_OT_text_add(struct wmOperatorType *ot); void OBJECT_OT_armature_add(struct wmOperatorType *ot); void OBJECT_OT_lamp_add(struct wmOperatorType *ot); -void OBJECT_OT_primitive_add(struct wmOperatorType *ot); /* only used as menu */ void OBJECT_OT_effector_add(struct wmOperatorType *ot); void OBJECT_OT_group_instance_add(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index f2f24c099bc..d75cf63c1d4 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -119,7 +119,6 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_add); WM_operatortype_append(OBJECT_OT_effector_add); WM_operatortype_append(OBJECT_OT_group_instance_add); - WM_operatortype_append(OBJECT_OT_primitive_add); WM_operatortype_append(OBJECT_OT_mesh_add); WM_operatortype_append(OBJECT_OT_metaball_add); WM_operatortype_append(OBJECT_OT_duplicates_make_real); @@ -247,7 +246,9 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "OBJECT_OT_delete", DELKEY, KM_PRESS, 0, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_primitive_add", AKEY, KM_PRESS, KM_SHIFT, 0); + kmi= WM_keymap_add_item(keymap, "WM_OT_call_menu", AKEY, KM_PRESS, KM_SHIFT, 0); + RNA_string_set(kmi->ptr, "name", "INFO_MT_add"); + WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_duplicate", DKEY, KM_PRESS, KM_ALT, 0)->ptr, "linked", 1); WM_keymap_add_item(keymap, "OBJECT_OT_join", JKEY, KM_PRESS, KM_CTRL, 0); diff --git a/source/blender/editors/space_node/node_header.c b/source/blender/editors/space_node/node_header.c index 2abcd2f2135..a0eae40f579 100644 --- a/source/blender/editors/space_node/node_header.c +++ b/source/blender/editors/space_node/node_header.c @@ -199,7 +199,7 @@ void node_menus_register(ARegionType *art) strcpy(mt->idname, "NODE_MT_add"); strcpy(mt->label, "Add"); mt->draw= node_menu_add; - BLI_addtail(&art->menutypes, mt); + WM_menutype_add(mt); } #if 0 diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 1a1172247fc..a1b412c70f4 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -348,12 +348,11 @@ static void rna_Menu_unregister(const bContext *C, StructRNA *type) if(!mt) return; - if(!(art=region_type_find(NULL, mt->space_type, RGN_TYPE_HEADER))) - return; RNA_struct_free_extension(type, &mt->ext); - BLI_freelinkN(&art->menutypes, mt); + WM_menutype_freelink(mt); + RNA_struct_free(&BLENDER_RNA, type); /* update while blender is running */ @@ -376,12 +375,9 @@ static StructRNA *rna_Menu_register(const bContext *C, ReportList *reports, void /* validate the python class */ if(validate(&dummymtr, data, have_function) != 0) return NULL; - - if(!(art=region_type_find(reports, dummymt.space_type, RGN_TYPE_HEADER))) - return NULL; /* check if we have registered this menu type before, and remove it */ - mt= BKE_spacemenu_find(dummymt.idname, dummymt.space_type); + mt= WM_menutype_find(dummymt.idname, TRUE); if(mt && mt->ext.srna) rna_Menu_unregister(C, mt->ext.srna); @@ -398,7 +394,7 @@ static StructRNA *rna_Menu_register(const bContext *C, ReportList *reports, void mt->poll= (have_function[0])? menu_poll: NULL; mt->draw= (have_function[1])? menu_draw: NULL; - BLI_addtail(&art->menutypes, mt); + WM_menutype_add(mt); /* update while blender is running */ if(C) @@ -734,11 +730,6 @@ static void rna_def_menu(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->label"); RNA_def_property_flag(prop, PROP_REGISTER); - prop= RNA_def_property(srna, "space_type", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_sdna(prop, NULL, "type->space_type"); - RNA_def_property_enum_items(prop, space_type_items); - RNA_def_property_flag(prop, PROP_REGISTER); - RNA_define_verify_sdna(1); } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 301204d3e2b..87752ca9c58 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -94,7 +94,7 @@ static PyObject *pyop_call( PyObject * self, PyObject * args) char *report_str= BKE_reports_string(reports, 0); /* all reports */ if(report_str) { - PySys_WriteStdout(report_str); + PySys_WriteStdout("%s\n", report_str); MEM_freeN(report_str); } } diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index b29dbec6364..eaf8b00163c 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -41,6 +41,7 @@ struct wmNotifier; struct rcti; struct PointerRNA; struct EnumPropertyItem; +struct MenuType; typedef struct wmJob wmJob; @@ -187,6 +188,12 @@ char *WM_operator_pystring(struct bContext *C, struct wmOperatorType *ot, struc void WM_operator_bl_idname(char *to, const char *from); void WM_operator_py_idname(char *to, const char *from); +/* *************** menu types ******************** */ +struct MenuType *WM_menutype_find(const char *idname, int quiet); +int WM_menutype_add(struct MenuType* mt); +void WM_menutype_freelink(struct MenuType* mt); +void WM_menutype_free(void); + /* default operator callbacks for border/circle/lasso */ int WM_border_select_invoke (struct bContext *C, struct wmOperator *op, struct wmEvent *event); int WM_border_select_modal (struct bContext *C, struct wmOperator *op, struct wmEvent *event); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index a068f84ae29..dbb8fc400c0 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -26,6 +26,8 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include "string.h" + #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -39,6 +41,7 @@ #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_screen.h" #include "BKE_report.h" #include "WM_api.h" @@ -128,6 +131,49 @@ void WM_operator_stack_clear(bContext *C) /* ****************************************** */ +static ListBase menutypes = {NULL, NULL}; /* global menutype list */ + +MenuType *WM_menutype_find(const char *idname, int quiet) +{ + MenuType* mt; + + if (idname[0]) { + for(mt=menutypes.first; mt; mt=mt->next) + if(strcmp(idname, mt->idname)==0) + return mt; + } + + if(!quiet) + printf("search for unknown menutype %s\n", idname); + + return NULL; +} + +int WM_menutype_add(MenuType* mt) +{ + BLI_addtail(&menutypes, mt); + return 1; +} + +void WM_menutype_freelink(MenuType* mt) +{ + BLI_freelinkN(&menutypes, mt); +} + +void WM_menutype_free(void) +{ + MenuType* mt; + + for(mt= menutypes.first; mt; mt= mt->next) { + if(mt->ext.free) { + mt->ext.free(mt->ext.data); + } + WM_menutype_freelink(mt); + } +} + +/* ****************************************** */ + void WM_keymap_init(bContext *C) { wmWindowManager *wm= CTX_wm_manager(C); diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 490ef12a523..2e456669cb1 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -195,6 +195,7 @@ void WM_exit(bContext *C) } } wm_operatortype_free(); + WM_menutype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if(C) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index a92fcee48e2..915f4c80663 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -783,7 +783,7 @@ static int wm_call_menu_invoke(bContext *C, wmOperator *op, wmEvent *event) char idname[BKE_ST_MAXNAME]; RNA_string_get(op->ptr, "name", idname); - uiPupMenuInvoke(C, idname, CTX_wm_area(C)->spacetype); + uiPupMenuInvoke(C, idname); return OPERATOR_CANCELLED; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 44b7b60e451..f7116a2bd1f 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -68,7 +68,6 @@ GHOST_SystemHandle g_system= NULL; /* set by commandline */ static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0; - /* ******** win open & close ************ */ /* XXX this one should correctly check for apple top header... diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index f159f7f098d..44c31e7cb69 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -62,6 +62,5 @@ void wm_window_testbreak (void); int wm_window_duplicate_op (bContext *C, wmOperator *op); int wm_window_fullscreen_toggle_op(bContext *C, wmOperator *op); - #endif /* WM_WINDOW_H */ From dadd8466d524ca8fa8a7152e88049f43d139b63d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 8 Oct 2009 19:32:06 +0000 Subject: [PATCH 045/138] scons - ignore removing _tkinter.so when its not there --- tools/Blender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Blender.py b/tools/Blender.py index fec11685525..38d2747889a 100644 --- a/tools/Blender.py +++ b/tools/Blender.py @@ -555,7 +555,7 @@ def UnixPyBundle(target=None, source=None, env=None): run('rm -rf "%s/site-packages"' % py_target) run('mkdir "%s/site-packages"' % py_target) # python needs it.' - run('rm "%s/lib-dynload/_tkinter.so"' % py_target) + run('rm -f "%s/lib-dynload/_tkinter.so"' % py_target) run('find "%s" -name "test" -prune -exec rm -rf {} \;' % py_target) run('find "%s" -name "*.py?" -exec rm -rf {} \;' % py_target) run('find "%s" -name "*.so"-exec strip -s {} \;' % py_target) From 1b6a09847a7a397810b154396b45161ccf97be36 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Fri, 9 Oct 2009 01:34:46 +0000 Subject: [PATCH 046/138] Partial revert of rev 23723 BRECHT, CHECK THIS The change made it return RNA python properties with null data pointer instead of None. That would make the particles and physics properties crash like this: 1. A valid property instead of None makes is seem like smoke (or other) modifier data is in context when it is Null. 2. UI code would try to access RNA properties of the (Null) modifier, which would crash --- source/blender/python/intern/bpy_rna.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 44b419e8ae9..ee202d7fcff 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -433,7 +433,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop) { PointerRNA newptr; newptr= RNA_property_pointer_get(ptr, prop); - if (newptr.type) { + if (newptr.data) { ret = pyrna_struct_CreatePyObject(&newptr); } else { ret = Py_None; @@ -1297,7 +1297,7 @@ static PyObject *pyrna_struct_getattro( BPy_StructRNA * self, PyObject *pyname ) CTX_data_get(self->ptr.data, name, &newptr, &newlb); - if (newptr.type) { + if (newptr.data) { ret = pyrna_struct_CreatePyObject(&newptr); } else if (newlb.first) { From cc4dd3f04e150613e8c160e4d58f4a557e59c63c Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Fri, 9 Oct 2009 01:52:57 +0000 Subject: [PATCH 047/138] netrender Support for fluid files and better support for point cache (including external cache for particles) This also fixes a couple of bugs with frame based dependencies and with file transfer. NOTE: With external point cache and fluids, the path needs to be relative or relative to the file (starting with //) if the files are not on a shared drive. It should eventually warn if that is not the case, but doesn't right now, so be careful. --- release/scripts/io/netrender/client.py | 144 +++++++++++++++---------- release/scripts/io/netrender/model.py | 2 +- release/scripts/io/netrender/utils.py | 2 +- 3 files changed, 91 insertions(+), 57 deletions(-) diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py index 1897d1fd949..d4a7b242cab 100644 --- a/release/scripts/io/netrender/client.py +++ b/release/scripts/io/netrender/client.py @@ -8,6 +8,68 @@ import netrender.slave as slave import netrender.master as master from netrender.utils import * +def addFluidFiles(job, path): + if os.path.exists(path): + pattern = re.compile("fluidsurface_(final|preview)_([0-9]+)\.(bobj|bvel)\.gz") + + for fluid_file in sorted(os.listdir(path)): + match = pattern.match(fluid_file) + + if match: + current_frame = int(match.groups()[1]) + job.addFile(path + fluid_file, current_frame, current_frame) + +def addPointCache(job, ob, point_cache, default_path): + if not point_cache.disk_cache: + return + + + name = point_cache.name + if name == "": + name = "".join(["%02X" % ord(c) for c in ob.name]) + + cache_path = bpy.sys.expandpath(point_cache.filepath) if point_cache.external else default_path + + index = "%02i" % point_cache.index + + if os.path.exists(cache_path): + pattern = re.compile(name + "_([0-9]+)_" + index + "\.bphys") + + cache_files = [] + + for cache_file in sorted(os.listdir(cache_path)): + match = pattern.match(cache_file) + + if match: + cache_frame = int(match.groups()[0]) + cache_files.append((cache_frame, cache_file)) + + cache_files.sort() + + if len(cache_files) == 1: + cache_frame, cache_file = cache_files[0] + job.addFile(cache_path + cache_file, cache_frame, cache_frame) + else: + for i in range(len(cache_files)): + current_item = cache_files[i] + next_item = cache_files[i+1] if i + 1 < len(cache_files) else None + previous_item = cache_files[i - 1] if i > 0 else None + + current_frame, current_file = current_item + + if not next_item and not previous_item: + job.addFile(cache_path + current_file, current_frame, current_frame) + elif next_item and not previous_item: + next_frame = next_item[0] + job.addFile(cache_path + current_file, current_frame, next_frame - 1) + elif not next_item and previous_item: + previous_frame = previous_item[0] + job.addFile(cache_path + current_file, previous_frame + 1, current_frame) + else: + next_frame = next_item[0] + previous_frame = previous_item[0] + job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1) + def clientSendJob(conn, scene, anim = False): netsettings = scene.network_render job = netrender.model.RenderJob() @@ -23,6 +85,7 @@ def clientSendJob(conn, scene, anim = False): job_name = netsettings.job_name path, name = os.path.split(filename) + path += os.sep if job_name == "[default]": job_name = name @@ -30,67 +93,38 @@ def clientSendJob(conn, scene, anim = False): # LIBRARIES ########################### for lib in bpy.data.libraries: - lib_path = lib.filename - - if lib_path.startswith("//"): - lib_path = path + os.sep + lib_path[2:] - - job.addFile(lib_path) - - ########################### - # POINT CACHES - ########################### - - root, ext = os.path.splitext(name) - cache_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that - - if os.path.exists(cache_path): - caches = {} - pattern = re.compile("([a-zA-Z0-9]+)_([0-9]+)_[0-9]+\.bphys") - for cache_file in sorted(os.listdir(cache_path)): - match = pattern.match(cache_file) - - if match: - cache_id = match.groups()[0] - cache_frame = int(match.groups()[1]) - - cache_files = caches.get(cache_id, []) - cache_files.append((cache_frame, cache_file)) - caches[cache_id] = cache_files - - for cache in caches.values(): - cache.sort() - - if len(cache) == 1: - cache_frame, cache_file = cache[0] - job.addFile(cache_path + cache_file, cache_frame, cache_frame) - else: - for i in range(len(cache)): - current_item = cache[i] - next_item = cache[i+1] if i + 1 < len(cache) else None - previous_item = cache[i - 1] if i > 0 else None - - current_frame, current_file = current_item - - if not next_item and not previous_item: - job.addFile(cache_path + current_file, current_frame, current_frame) - elif next_item and not previous_item: - next_frame = next_item[0] - job.addFile(cache_path + current_file, current_frame, next_frame - 1) - elif not next_item and previous_item: - previous_frame = previous_item[0] - job.addFile(cache_path + current_file, previous_frame + 1, current_frame) - else: - next_frame = next_item[0] - previous_frame = previous_item[0] - job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1) + job.addFile(bpy.sys.expandpath(lib_path)) ########################### # IMAGES ########################### for image in bpy.data.images: if image.source == "FILE" and not image.packed_file: - job.addFile(image.filename) + job.addFile(bpy.sys.expandpath(image.filename)) + + ########################### + # FLUID + POINT CACHE + ########################### + root, ext = os.path.splitext(name) + default_path = path + "blendcache_" + root + os.sep # need an API call for that + + for object in bpy.data.objects: + for modifier in object.modifiers: + if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN": + addFluidFiles(job, bpy.sys.expandpath(modifier.settings.path)) + elif modifier.type == "CLOTH": + addPointCache(job, object, modifier.point_cache, default_path) + elif modifier.type == "SOFT_BODY": + addPointCache(job, object, modifier.point_cache, default_path) + elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN": + addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path) + if modifier.domain_settings.highres: + addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path) + + # particles modifier are stupid and don't contain data + # we have to go through the object property + for psys in object.particle_systems: + addPointCache(job, object, psys.point_cache, default_path) # print(job.files) diff --git a/release/scripts/io/netrender/model.py b/release/scripts/io/netrender/model.py index ca2a42d87f6..bef6f0e68af 100644 --- a/release/scripts/io/netrender/model.py +++ b/release/scripts/io/netrender/model.py @@ -149,7 +149,7 @@ class RenderJob: "id": self.id, "type": self.type, "name": self.name, - "files": [f for f in self.files if f[1] == -1 or not frames or (f[1] <= min_frame <= f[2] or f[1] <= max_frame <= f[2])], + "files": [f for f in self.files if f[1] == -1 or not frames or (f[1] <= max_frame and f[2] >= min_frame)], "frames": [f.serialize() for f in self.frames if not frames or f in frames], "chunks": self.chunks, "priority": self.priority, diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py index 06393a738a0..b10648b8d62 100644 --- a/release/scripts/io/netrender/utils.py +++ b/release/scripts/io/netrender/utils.py @@ -75,7 +75,7 @@ def prefixPath(prefix_directory, file_path, prefix_path): if prefix_path and p.startswith(prefix_path): directory = prefix_directory + p[len(prefix_path):] - full_path = directory + n + full_path = directory + os.sep + n if not os.path.exists(directory): os.mkdir(directory) else: From 9ebcd9c5e46c8addd80c8adb97fcee91a1916d57 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 9 Oct 2009 09:48:04 +0000 Subject: [PATCH 048/138] A few bugfixes: * #19583: Keying Sets list issues Deleting a Keying Set (or a Keying Set Path) set the active index to 0, but that would mean that the first item would be selected but not visible. * #19590: Keyframing properties of a modifier with more than one of it's type the property will highlight in all - Modifiers now always have a unique name, so renaming a modifier should check that the name is unique. Most of the files changed in this commit were just to make sure that modifiers got unique names when they were created - Modifiers path getter was wrapped a bit wrong (missing the "s around the name) * Constraints Bugs - Constraints renaming now also makes sure the names stay unique - Fixed (or attempted to fix) compiler warnings about some enum declaration for distance constraint --- source/blender/blenkernel/BKE_modifier.h | 2 ++ source/blender/blenkernel/intern/modifier.c | 13 ++++++- source/blender/blenkernel/intern/multires.c | 1 + source/blender/blenloader/intern/readfile.c | 4 +++ source/blender/editors/animation/keyingsets.c | 9 ++--- .../editors/interface/interface_templates.c | 2 ++ source/blender/editors/object/object_edit.c | 8 +++-- source/blender/editors/object/object_hook.c | 1 + .../blender/editors/object/object_modifier.c | 22 ++++++++---- .../blender/makesrna/intern/rna_constraint.c | 34 +++++++++++++++---- source/blender/makesrna/intern/rna_fluidsim.c | 1 + source/blender/makesrna/intern/rna_modifier.c | 18 +++++++++- 12 files changed, 94 insertions(+), 21 deletions(-) diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 27c75126026..9957ced9555 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -274,6 +274,8 @@ ModifierTypeInfo *modifierType_getInfo (ModifierType type); struct ModifierData *modifier_new(int type); void modifier_free(struct ModifierData *md); +void modifier_unique_name(struct ListBase *modifiers, struct ModifierData *md); + void modifier_copyData(struct ModifierData *md, struct ModifierData *target); int modifier_dependsOnTime(struct ModifierData *md); int modifier_supportsMapping(struct ModifierData *md); diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index f36713dd8a9..532c3e5da73 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -34,6 +34,7 @@ * */ +#include "stddef.h" #include "string.h" #include "stdarg.h" #include "math.h" @@ -8761,7 +8762,8 @@ ModifierData *modifier_new(int type) { ModifierTypeInfo *mti = modifierType_getInfo(type); ModifierData *md = MEM_callocN(mti->structSize, mti->structName); - + + // FIXME: we need to make the name always be unique somehow... strcpy(md->name, mti->name); md->type = type; @@ -8786,6 +8788,15 @@ void modifier_free(ModifierData *md) MEM_freeN(md); } +void modifier_unique_name(ListBase *modifiers, ModifierData *md) +{ + if (modifiers && md) { + ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + BLI_uniquename(modifiers, md, mti->name, '.', offsetof(ModifierData, name), sizeof(md->name)); + } +} + int modifier_dependsOnTime(ModifierData *md) { ModifierTypeInfo *mti = modifierType_getInfo(md->type); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index e7159b82d49..ecffbb3d15f 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -142,6 +142,7 @@ void multiresModifier_join(Object *ob) mmd = (MultiresModifierData*)modifier_new(eModifierType_Multires); BLI_insertlinkbefore(&base->object->modifiers, md, mmd); + modifier_unique_name(&base->object->modifiers, mmd); } if(mmd) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f2bf8b19bc6..49dae2af168 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4095,6 +4095,8 @@ static void direct_link_object(FileData *fd, Object *ob) BLI_addhead(&ob->modifiers, hmd); BLI_remlink(&ob->hooks, hook); + + modifier_unique_name(&ob->modifiers, hmd); MEM_freeN(hook); } @@ -7659,6 +7661,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main) smd->flags |= eSubsurfModifierFlag_ControlEdges; BLI_addtail(&ob->modifiers, smd); + + modifier_unique_name(&ob->modifiers, smd); } } diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c index d1ac624ec6f..a044e867d56 100644 --- a/source/blender/editors/animation/keyingsets.c +++ b/source/blender/editors/animation/keyingsets.c @@ -177,9 +177,10 @@ static int remove_active_keyingset_exec (bContext *C, wmOperator *op) /* free KeyingSet's data, then remove it from the scene */ BKE_keyingset_free(ks); - BLI_freelinkN(&scene->keyingsets, ks); - scene->active_keyingset= 0; + + /* the active one should now be the previously second-to-last one */ + scene->active_keyingset--; return OPERATOR_FINISHED; } @@ -258,8 +259,8 @@ static int remove_active_ks_path_exec (bContext *C, wmOperator *op) BLI_freelinkN(&ks->paths, ksp); } - /* fix active path index */ - ks->active_path= 0; + /* the active path should now be the previously second-to-last active one */ + ks->active_path--; } else { BKE_report(op->reports, RPT_ERROR, "No active Keying Set Path to remove"); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index d94d2be3a94..24bff19555f 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -458,6 +458,8 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v) nmd->mode &= ~eModifierMode_Virtual; BLI_addhead(&ob->modifiers, nmd); + + modifier_unique_name(&ob->modifiers, nmd); ob->partype = PAROBJECT; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 268cd3b3542..55f95f451d2 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -848,6 +848,7 @@ void special_editmenu(Scene *scene, View3D *v3d) BooleanModifierData *bmd = NULL; bmd = (BooleanModifierData *)modifier_new(eModifierType_Boolean); BLI_addtail(&ob->modifiers, bmd); + modifier_unique_name(&ob->modifiers, bmd); bmd->object = base_select->object; bmd->modifier.mode |= eModifierMode_Realtime; switch(nr){ @@ -978,9 +979,10 @@ static void object_flip_subdivison_particles(Scene *scene, Object *ob, int *set, } else if(depth == 0 && *set != 0) { SubsurfModifierData *smd = (SubsurfModifierData*) modifier_new(eModifierType_Subsurf); - + BLI_addtail(&ob->modifiers, smd); - + modifier_unique_name(&ob->modifiers, smd); + if (level!=-1) { smd->levels = level; } @@ -1197,6 +1199,7 @@ static void copymenu_modifiers(Scene *scene, View3D *v3d, Object *ob) nmd = modifier_new(md->type); modifier_copyData(md, nmd); BLI_addtail(&base->object->modifiers, nmd); + modifier_unique_name(&base->object->modifiers, nmd); } copy_object_particlesystems(base->object, ob); @@ -1220,6 +1223,7 @@ static void copymenu_modifiers(Scene *scene, View3D *v3d, Object *ob) mdn = modifier_new(event); BLI_addtail(&base->object->modifiers, mdn); + modifier_unique_name(&base->object->modifiers, mdn); modifier_copyData(md, mdn); } diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index ab7bcbc989d..63182e943bb 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -480,6 +480,7 @@ void add_hook(Scene *scene, View3D *v3d, int mode) hmd = (HookModifierData*) modifier_new(eModifierType_Hook); BLI_insertlinkbefore(&obedit->modifiers, md, hmd); sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2); + modifier_unique_name(&obedit->modifiers, hmd); } else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */ diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 7f0f1876417..252fdb5522a 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -76,7 +76,7 @@ int ED_object_modifier_add(ReportList *reports, Scene *scene, Object *ob, int type) { - ModifierData *md; + ModifierData *md=NULL, *new_md=NULL; ModifierTypeInfo *mti = modifierType_getInfo(type); if(mti->flags&eModifierTypeFlag_Single) { @@ -87,19 +87,28 @@ int ED_object_modifier_add(ReportList *reports, Scene *scene, Object *ob, int ty } if(type == eModifierType_ParticleSystem) { + /* don't need to worry about the new modifier's name, since that is set to the number + * of particle systems which shouldn't have too many duplicates + */ object_add_particle_system(scene, ob); } else { + /* get new modifier data to add */ + new_md= modifier_new(type); + if(mti->flags&eModifierTypeFlag_RequiresOriginalData) { md = ob->modifiers.first; - + while(md && modifierType_getInfo(md->type)->type==eModifierTypeType_OnlyDeform) md = md->next; - - BLI_insertlinkbefore(&ob->modifiers, md, modifier_new(type)); + + BLI_insertlinkbefore(&ob->modifiers, md, new_md); } else - BLI_addtail(&ob->modifiers, modifier_new(type)); + BLI_addtail(&ob->modifiers, new_md); + + /* make sure modifier data has unique name */ + modifier_unique_name(&ob->modifiers, new_md); /* special cases */ if(type == eModifierType_Softbody) { @@ -111,7 +120,7 @@ int ED_object_modifier_add(ReportList *reports, Scene *scene, Object *ob, int ty else if(type == eModifierType_Collision) { if(!ob->pd) ob->pd= object_add_collision_fields(0); - + ob->pd->deflect= 1; DAG_scene_sort(scene); } @@ -400,6 +409,7 @@ int ED_object_modifier_copy(ReportList *reports, Object *ob, ModifierData *md) nmd = modifier_new(md->type); modifier_copyData(md, nmd); BLI_insertlink(&ob->modifiers, md, nmd); + modifier_unique_name(&ob->modifiers, nmd); return 1; } diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index e6d8a2f27d7..325318ba34a 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -87,13 +87,6 @@ EnumPropertyItem constraint_ik_type_items[] ={ {0, NULL, 0, NULL, NULL}, }; -EnumPropertyItem constraint_distance_items[] = { - {LIMITDIST_INSIDE, "LIMITDIST_INSIDE", 0, "Inside", ""}, - {LIMITDIST_OUTSIDE, "LIMITDIST_OUTSIDE", 0, "Outside", ""}, - {LIMITDIST_ONSURFACE, "LIMITDIST_ONSURFACE", 0, "On Surface", ""}, - {0, NULL, 0, NULL, NULL} -}; - #ifdef RNA_RUNTIME #include "BKE_action.h" @@ -153,6 +146,24 @@ static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) } } +static void rna_Constraint_name_set(PointerRNA *ptr, const char *value) +{ + bConstraint *con= ptr->data; + + /* copy the new name into the name slot */ + BLI_strncpy(con->name, value, sizeof(con->name)); + + /* make sure name is unique */ + if (ptr->id.data) { + Object *ob= ptr->id.data; + ListBase *list= get_active_constraints(ob); + + /* if we have the list, check for unique name, otherwise give up */ + if (list) + unique_constraint_name(con, list); + } +} + static char *rna_Constraint_path(PointerRNA *ptr) { Object *ob= ptr->id.data; @@ -291,6 +302,14 @@ static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float #else +EnumPropertyItem constraint_distance_items[] = { + {LIMITDIST_INSIDE, "LIMITDIST_INSIDE", 0, "Inside", ""}, + {LIMITDIST_OUTSIDE, "LIMITDIST_OUTSIDE", 0, "Outside", ""}, + {LIMITDIST_ONSURFACE, "LIMITDIST_ONSURFACE", 0, "On Surface", ""}, + {0, NULL, 0, NULL, NULL} +}; + + static void rna_def_constrainttarget(BlenderRNA *brna) { StructRNA *srna; @@ -1606,6 +1625,7 @@ void RNA_def_constraint(BlenderRNA *brna) /* strings */ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Constraint_name_set"); RNA_def_property_ui_text(prop, "Name", ""); RNA_def_struct_name_property(srna, prop); diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index c415b3d716a..5b05948857e 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -114,6 +114,7 @@ static void rna_FluidSettings_update_type(bContext *C, PointerRNA *ptr) sprintf(psmd->modifier.name, "FluidParticleSystem" ); psmd->psys= psys; BLI_addtail(&ob->modifiers, psmd); + modifier_unique_name(&ob->modifiers, psmd); } } else { diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 480abff19cb..b04f0a865ef 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -85,6 +85,7 @@ EnumPropertyItem modifier_type_items[] ={ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_library.h" +#include "BKE_modifier.h" static void rna_UVProject_projectors_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { @@ -164,9 +165,23 @@ static StructRNA* rna_Modifier_refine(struct PointerRNA *ptr) } } +void rna_Modifier_name_set(PointerRNA *ptr, const char *value) +{ + ModifierData *md= ptr->data; + + /* copy the new name into the name slot */ + BLI_strncpy(md->name, value, sizeof(md->name)); + + /* make sure the name is truly unique */ + if (ptr->id.data) { + Object *ob= ptr->id.data; + modifier_unique_name(&ob->modifiers, md); + } +} + static char *rna_Modifier_path(PointerRNA *ptr) { - return BLI_sprintfN("modifiers[%s]", ((ModifierData*)ptr->data)->name); // XXX not unique + return BLI_sprintfN("modifiers[\"%s\"]", ((ModifierData*)ptr->data)->name); } static void rna_Modifier_update(bContext *C, PointerRNA *ptr) @@ -1911,6 +1926,7 @@ void RNA_def_modifier(BlenderRNA *brna) /* strings */ prop= RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Modifier_name_set"); RNA_def_property_ui_text(prop, "Name", "Modifier name."); RNA_def_struct_name_property(srna, prop); From 2226a5139a2ad78d4de2eaaf09e734adf1ce0ae4 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 09:50:49 +0000 Subject: [PATCH 049/138] Fix some issues with showing the current textures when using material nodes and texture nodes. Made it all use the same give_current_*_texture functions now. --- release/scripts/ui/buttons_texture.py | 8 +- source/blender/blenkernel/BKE_texture.h | 25 ++-- source/blender/blenkernel/intern/texture.c | 110 ++++++++++-------- .../editors/space_buttons/buttons_context.c | 14 +-- source/blender/editors/space_node/node_edit.c | 12 +- 5 files changed, 93 insertions(+), 76 deletions(-) diff --git a/release/scripts/ui/buttons_texture.py b/release/scripts/ui/buttons_texture.py index c4866edcaaa..b76f35c3ec3 100644 --- a/release/scripts/ui/buttons_texture.py +++ b/release/scripts/ui/buttons_texture.py @@ -75,11 +75,13 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel): layout.itemR(tex, "use_nodes") split = layout.split(percentage=0.2) - + if tex.use_nodes: slot = context.texture_slot - split.itemL(text="Output:") - split.itemR(slot, "output_node", text="") + + if slot: + split.itemL(text="Output:") + split.itemR(slot, "output_node", text="") else: split.itemL(text="Type:") diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index a9862ba586b..407dc94adfa 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -31,17 +31,20 @@ #ifndef BKE_TEXTURE_H #define BKE_TEXTURE_H -struct Scene; -struct Tex; +struct Brush; +struct ColorBand; +struct EnvMap; +struct HaloRen; +struct Lamp; +struct LampRen; +struct Material; struct MTex; struct PluginTex; -struct LampRen; -struct ColorBand; -struct HaloRen; -struct TexMapping; -struct EnvMap; struct PointDensity; +struct Tex; +struct TexMapping; struct VoxelData; +struct World; /* in ColorBand struct */ #define MAXCOLORBAND 32 @@ -65,8 +68,12 @@ struct MTex *add_mtex(void); struct Tex *copy_texture(struct Tex *tex); void make_local_texture(struct Tex *tex); void autotexname(struct Tex *tex); -struct Tex *give_current_texture(struct Object *ob, int act); -struct Tex *give_current_world_texture(struct Scene *scene); + +struct Tex *give_current_object_texture(struct Object *ob); +struct Tex *give_current_material_texture(struct Material *ma); +struct Tex *give_current_lamp_texture(struct Lamp *la); +struct Tex *give_current_world_texture(struct World *world); +struct Tex *give_current_brush_texture(struct Brush *br); struct TexMapping *add_mapping(void); void init_mapping(struct TexMapping *texmap); diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index 3b8ae9a6c7f..f09abf93bb8 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -809,72 +809,90 @@ void autotexname(Tex *tex) /* ------------------------------------------------------------------------- */ -Tex *give_current_texture(Object *ob, int act) +Tex *give_current_object_texture(Object *ob) { - Material ***matarar, *ma; - Lamp *la = 0; - MTex *mtex = 0; - Tex *tex = 0; - bNode *node; + Material *ma; + Tex *tex= NULL; if(ob==0) return 0; if(ob->totcol==0 && !(ob->type==OB_LAMP)) return 0; if(ob->type==OB_LAMP) { - la=(Lamp *)ob->data; - if(la) { - mtex= la->mtex[(int)(la->texact)]; - if(mtex) tex= mtex->tex; - } + tex= give_current_lamp_texture(ob->data); } else { - if(act>ob->totcol) act= ob->totcol; - else if(act==0) act= 1; - - if(ob->matbits[act-1]) { /* in object */ - ma= ob->mat[act-1]; - } - else { /* in data */ - matarar= give_matarar(ob); - - if(matarar && *matarar) ma= (*matarar)[act-1]; - else ma= 0; - } - - if(ma && ma->use_nodes && ma->nodetree) { - node= nodeGetActiveID(ma->nodetree, ID_TE); - - if(node) { - tex= (Tex *)node->id; - ma= NULL; - } - else { - node= nodeGetActiveID(ma->nodetree, ID_MA); - if(node) - ma= (Material*)node->id; - } - } - if(ma) { - mtex= ma->mtex[(int)(ma->texact)]; - if(mtex) tex= mtex->tex; - } + ma= give_current_material(ob, ob->actcol); + tex= give_current_material_texture(ma); } return tex; } -Tex *give_current_world_texture(Scene *scene) +Tex *give_current_lamp_texture(Lamp *la) { - MTex *mtex = 0; - Tex *tex = 0; + MTex *mtex= NULL; + Tex *tex= NULL; + + if(la) { + mtex= la->mtex[(int)(la->texact)]; + if(mtex) tex= mtex->tex; + } + + return tex; +} + +Tex *give_current_material_texture(Material *ma) +{ + MTex *mtex= NULL; + Tex *tex= NULL; + bNode *node; - if(!(scene->world)) return 0; + if(ma && ma->use_nodes && ma->nodetree) { + node= nodeGetActiveID(ma->nodetree, ID_TE); + + if(node) { + tex= (Tex *)node->id; + ma= NULL; + } + else { + node= nodeGetActiveID(ma->nodetree, ID_MA); + if(node) + ma= (Material*)node->id; + } + } + if(ma) { + mtex= ma->mtex[(int)(ma->texact)]; + if(mtex) tex= mtex->tex; + } - mtex= scene->world->mtex[(int)(scene->world->texact)]; + return tex; +} + +Tex *give_current_world_texture(World *world) +{ + MTex *mtex= NULL; + Tex *tex= NULL; + + if(!world) return 0; + + mtex= world->mtex[(int)(world->texact)]; if(mtex) tex= mtex->tex; return tex; } +Tex *give_current_brush_texture(Brush *br) +{ + MTex *mtex= NULL; + Tex *tex= NULL; + + if(br) { + mtex= br->mtex[(int)(br->texact)]; + if(mtex) tex= mtex->tex; + } + + return tex; +} + /* ------------------------------------------------------------------------- */ EnvMap *BKE_add_envmap(void) diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 9333ba9209c..a5a7524e584 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -52,6 +52,7 @@ #include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_screen.h" +#include "BKE_texture.h" #include "BKE_utildefines.h" #include "BKE_world.h" @@ -342,7 +343,6 @@ static int buttons_context_path_texture(const bContext *C, ButsContextPath *path Lamp *la; Brush *br; World *wo; - MTex *mtex; Tex *tex; PointerRNA *ptr= &path->ptr[path->len-1]; @@ -355,8 +355,7 @@ static int buttons_context_path_texture(const bContext *C, ButsContextPath *path br= path->ptr[path->len-1].data; if(br) { - mtex= br->mtex[(int)br->texact]; - tex= (mtex)? mtex->tex: NULL; + tex= give_current_brush_texture(br); RNA_id_pointer_create(&tex->id, &path->ptr[path->len]); path->len++; @@ -368,8 +367,7 @@ static int buttons_context_path_texture(const bContext *C, ButsContextPath *path wo= path->ptr[path->len-1].data; if(wo) { - mtex= wo->mtex[(int)wo->texact]; - tex= (mtex)? mtex->tex: NULL; + give_current_world_texture(wo); RNA_id_pointer_create(&tex->id, &path->ptr[path->len]); path->len++; @@ -381,8 +379,7 @@ static int buttons_context_path_texture(const bContext *C, ButsContextPath *path ma= path->ptr[path->len-1].data; if(ma) { - mtex= ma->mtex[(int)ma->texact]; - tex= (mtex)? mtex->tex: NULL; + tex= give_current_material_texture(ma); RNA_id_pointer_create(&tex->id, &path->ptr[path->len]); path->len++; @@ -394,8 +391,7 @@ static int buttons_context_path_texture(const bContext *C, ButsContextPath *path la= path->ptr[path->len-1].data; if(la) { - mtex= la->mtex[(int)la->texact]; - tex= (mtex)? mtex->tex: NULL; + tex= give_current_lamp_texture(la); RNA_id_pointer_create(&tex->id, &path->ptr[path->len]); path->len++; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index cee90b5a148..13421adf6e6 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -645,7 +645,7 @@ void snode_set_context(SpaceNode *snode, Scene *scene) if(snode->texfrom==SNODE_TEX_OBJECT) { if(ob) { - tx= give_current_texture(ob, ob->actcol); + tx= give_current_object_texture(ob); if(ob->type == OB_LAMP) snode->from= (ID*)ob->data; @@ -656,11 +656,10 @@ void snode_set_context(SpaceNode *snode, Scene *scene) } } else if(snode->texfrom==SNODE_TEX_WORLD) { - tx= give_current_world_texture(scene); + tx= give_current_world_texture(scene->world); snode->from= (ID *)scene->world; } else { - MTex *mtex= NULL; Brush *brush= NULL; if(ob && (ob->mode & OB_MODE_SCULPT)) @@ -668,13 +667,8 @@ void snode_set_context(SpaceNode *snode, Scene *scene) else brush= paint_brush(&scene->toolsettings->imapaint.paint); - if(brush && brush->texact != -1) - mtex= brush->mtex[brush->texact]; - snode->from= (ID *)brush; - - if(mtex) - tx= mtex->tex; + tx= give_current_brush_texture(brush); } snode->id= &tx->id; From be3da5dfffd23b0dc2f9bffc2e7d2012f1c63494 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 10:45:11 +0000 Subject: [PATCH 050/138] 3D View panels now show object and bone name again, not sure it belongs here still, but this came up often, it avoids having to switch tabs a lot when creating things. Also renamed uiLayoutFreeBlock to uiLayoutAbsoluteBlock. --- source/blender/editors/include/UI_interface.h | 2 +- .../editors/interface/interface_layout.c | 22 +++---- .../editors/interface/interface_templates.c | 8 +-- .../editors/space_graph/graph_buttons.c | 4 +- .../editors/space_image/image_buttons.c | 2 +- .../editors/space_logic/logic_buttons.c | 4 +- source/blender/editors/space_node/drawnode.c | 48 +++++++------- .../space_sequencer/sequencer_buttons.c | 4 +- .../editors/space_view3d/view3d_buttons.c | 62 ++++++++++++++----- .../editors/space_view3d/view3d_header.c | 2 +- 10 files changed, 96 insertions(+), 62 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 5766fcfdb1f..adbfd731a09 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -614,7 +614,7 @@ uiLayout *uiLayoutListBox(uiLayout *layout); uiLayout *uiLayoutFree(uiLayout *layout, int align); uiLayout *uiLayoutSplit(uiLayout *layout, float percentage); -uiBlock *uiLayoutFreeBlock(uiLayout *layout); +uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout); /* templates */ void uiTemplateHeader(uiLayout *layout, struct bContext *C, int menus); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b0f93472240..233d3b214ae 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -96,7 +96,7 @@ typedef enum uiItemType { ITEM_LAYOUT_COLUMN_FLOW, ITEM_LAYOUT_ROW_FLOW, ITEM_LAYOUT_BOX, - ITEM_LAYOUT_FREE, + ITEM_LAYOUT_ABSOLUTE, ITEM_LAYOUT_SPLIT, ITEM_LAYOUT_ROOT @@ -290,7 +290,7 @@ static int ui_layout_local_dir(uiLayout *layout) case ITEM_LAYOUT_COLUMN: case ITEM_LAYOUT_COLUMN_FLOW: case ITEM_LAYOUT_SPLIT: - case ITEM_LAYOUT_FREE: + case ITEM_LAYOUT_ABSOLUTE: case ITEM_LAYOUT_BOX: default: return UI_LAYOUT_VERTICAL; @@ -1731,7 +1731,7 @@ static void ui_litem_layout_column_flow(uiLayout *litem) } /* free layout */ -static void ui_litem_estimate_free(uiLayout *litem) +static void ui_litem_estimate_absolute(uiLayout *litem) { uiItem *item; int itemx, itemy, itemw, itemh, minx, miny; @@ -1756,7 +1756,7 @@ static void ui_litem_estimate_free(uiLayout *litem) litem->h -= miny; } -static void ui_litem_layout_free(uiLayout *litem) +static void ui_litem_layout_absolute(uiLayout *litem) { uiItem *item; float scalex=1.0f, scaley=1.0f; @@ -1962,7 +1962,7 @@ uiLayout *uiLayoutFree(uiLayout *layout, int align) uiLayout *litem; litem= MEM_callocN(sizeof(uiLayout), "uiLayoutFree"); - litem->item.type= ITEM_LAYOUT_FREE; + litem->item.type= ITEM_LAYOUT_ABSOLUTE; litem->root= layout->root; litem->align= align; litem->active= 1; @@ -1975,7 +1975,7 @@ uiLayout *uiLayoutFree(uiLayout *layout, int align) return litem; } -uiBlock *uiLayoutFreeBlock(uiLayout *layout) +uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout) { uiBlock *block; @@ -2136,8 +2136,8 @@ static void ui_item_estimate(uiItem *item) case ITEM_LAYOUT_ROOT: ui_litem_estimate_root(litem); break; - case ITEM_LAYOUT_FREE: - ui_litem_estimate_free(litem); + case ITEM_LAYOUT_ABSOLUTE: + ui_litem_estimate_absolute(litem); break; case ITEM_LAYOUT_SPLIT: ui_litem_estimate_split(litem); @@ -2161,7 +2161,7 @@ static void ui_item_align(uiLayout *litem, int nr) if(!bitem->but->alignnr) bitem->but->alignnr= nr; } - else if(item->type == ITEM_LAYOUT_FREE); + else if(item->type == ITEM_LAYOUT_ABSOLUTE); else if(item->type == ITEM_LAYOUT_BOX) { box= (uiLayoutItemBx*)item; box->roundbox->alignnr= nr; @@ -2221,8 +2221,8 @@ static void ui_item_layout(uiItem *item) case ITEM_LAYOUT_ROOT: ui_litem_layout_root(litem); break; - case ITEM_LAYOUT_FREE: - ui_litem_layout_free(litem); + case ITEM_LAYOUT_ABSOLUTE: + ui_litem_layout_absolute(litem); break; case ITEM_LAYOUT_SPLIT: ui_litem_layout_split(litem); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 24bff19555f..7f768a42956 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -61,7 +61,7 @@ void uiTemplateHeader(uiLayout *layout, bContext *C, int menus) { uiBlock *block; - block= uiLayoutFreeBlock(layout); + block= uiLayoutAbsoluteBlock(layout); if(menus) ED_area_header_standardbuttons(C, block, 0); else ED_area_header_switchbutton(C, block, 0); } @@ -603,7 +603,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Object *ob, ModifierData *md, i } result= uiLayoutColumn(box, 0); - block= uiLayoutFreeBlock(box); + block= uiLayoutAbsoluteBlock(box); } if(md->error) { @@ -948,7 +948,7 @@ static uiLayout *draw_constraint(uiLayout *layout, Object *ob, bConstraint *con) } else { box= uiLayoutBox(col); - block= uiLayoutFreeBlock(box); + block= uiLayoutAbsoluteBlock(box); switch (con->type) { #ifndef DISABLE_PYTHON @@ -1459,7 +1459,7 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, char *propname, int rect.xmin= 0; rect.xmax= 200; rect.ymin= 0; rect.ymax= 190; - block= uiLayoutFreeBlock(layout); + block= uiLayoutAbsoluteBlock(layout); colorband_buttons_layout(block, cptr.data, &rect, !expand, cb); MEM_freeN(cb); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 09008f8d2d1..afc86309ffb 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -146,7 +146,7 @@ static void graph_panel_properties(const bContext *C, Panel *pa) if(!graph_panel_context(C, &ale, &fcu)) return; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL); /* Info - Active F-Curve */ @@ -285,7 +285,7 @@ static void graph_panel_drivers(const bContext *C, Panel *pa) driver= fcu->driver; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_graph_region_driver_buttons, NULL); /* general actions */ diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index 67fb95b1f6b..e2990a6d919 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -1105,7 +1105,7 @@ static void image_panel_uv(const bContext *C, Panel *pa) ARegion *ar= CTX_wm_region(C); uiBlock *block; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_image_panel_events, NULL); image_editvertex_buts(C, block); diff --git a/source/blender/editors/space_logic/logic_buttons.c b/source/blender/editors/space_logic/logic_buttons.c index 304c3601cdd..5761432ee29 100644 --- a/source/blender/editors/space_logic/logic_buttons.c +++ b/source/blender/editors/space_logic/logic_buttons.c @@ -83,7 +83,7 @@ static void logic_panel_properties(const bContext *C, Panel *pa) // SpaceLogic *slogic= CTX_wm_space_logic(C); uiBlock *block; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_logic_panel_events, NULL); } @@ -93,7 +93,7 @@ static void logic_panel_view_properties(const bContext *C, Panel *pa) // SpaceLogic *slogic= CTX_wm_space_logic(C); uiBlock *block; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_logic_panel_events, NULL); } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 33be0b83f20..42c664520fe 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -173,7 +173,7 @@ static void node_group_alone_cb(bContext *C, void *node_v, void *unused_v) static void node_buts_group(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; @@ -207,7 +207,7 @@ static void node_buts_group(uiLayout *layout, PointerRNA *ptr) static void node_buts_value(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; bNodeSocket *sock= node->outputs.first; /* first socket stores value */ @@ -219,7 +219,7 @@ static void node_buts_value(uiLayout *layout, PointerRNA *ptr) static void node_buts_rgb(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; bNodeSocket *sock= node->outputs.first; /* first socket stores value */ @@ -279,7 +279,7 @@ static void node_buts_time(uiLayout *layout, PointerRNA *ptr) static void node_buts_valtorgb(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; @@ -316,7 +316,7 @@ static void node_buts_curvecol(uiLayout *layout, PointerRNA *ptr) static void node_buts_normal(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; bNodeSocket *sock= node->outputs.first; /* first socket stores normal */ @@ -389,7 +389,7 @@ static void node_dynamic_update_cb(bContext *C, void *ntree_v, void *node_v) static void node_buts_texture(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -432,7 +432,7 @@ static void node_buts_texture(uiLayout *layout, PointerRNA *ptr) static void node_buts_math(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; uiBut *bt; @@ -544,7 +544,7 @@ static void node_texmap_cb(bContext *C, void *texmap_v, void *unused_v) static void node_shader_buts_material(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -616,7 +616,7 @@ static void node_shader_buts_material(uiLayout *layout, PointerRNA *ptr) static void node_shader_buts_mapping(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; TexMapping *texmap= node->storage; @@ -664,7 +664,7 @@ static void node_shader_buts_mapping(uiLayout *layout, PointerRNA *ptr) static void node_shader_buts_vect_math(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; uiBut *bt; @@ -675,7 +675,7 @@ static void node_shader_buts_vect_math(uiLayout *layout, PointerRNA *ptr) static void node_shader_buts_geometry(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; uiBut *but; @@ -694,7 +694,7 @@ static void node_shader_buts_geometry(uiLayout *layout, PointerRNA *ptr) static void node_shader_buts_dynamic(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -867,7 +867,7 @@ static void image_layer_cb(bContext *C, void *ima_v, void *iuser_v) static void node_composit_buts_image(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -1035,7 +1035,7 @@ static void node_browse_scene_cb(bContext *C, void *ntree_v, void *node_v) static void node_composit_buts_renderlayers(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -1402,7 +1402,7 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, PointerRNA *ptr) uiItemR(col, NULL, 0, ptr, "gain", UI_ITEM_R_SLIDER); uiItemR(col, NULL, 0, ptr, "shadow_adjust", UI_ITEM_R_SLIDER); -// uiBlock *block= uiLayoutFreeBlock(layout); +// uiBlock *block= uiLayoutAbsoluteBlock(layout); // bNode *node= ptr->data; // rctf *butr= &node->butr; // short dx=(butr->xmax-butr->xmin)/2; @@ -1435,7 +1435,7 @@ static void node_composit_buts_color_matte(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_channel_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; short sx= (butr->xmax-butr->xmin)/4; @@ -1492,7 +1492,7 @@ static void node_composit_buts_channel_matte(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_luma_matte(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; NodeChroma *c=node->storage; @@ -1519,7 +1519,7 @@ static void node_composit_buts_map_uv(uiLayout *layout, PointerRNA *ptr) static void node_composit_buts_id_mask(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; @@ -1554,7 +1554,7 @@ static void node_set_image_cb(bContext *C, void *ntree_v, void *node_v) static void node_composit_buts_file_output(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -1626,7 +1626,7 @@ static void node_scale_cb(bContext *C, void *node_v, void *unused_v) static void node_composit_buts_scale(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; uiBut *bt= uiDefButS(block, MENU, B_NODE_EXEC, "Relative %x0|Absolute %x1|Scene Size % %x2|", @@ -1799,7 +1799,7 @@ static void node_composit_set_butfunc(bNodeType *ntype) static void node_texture_buts_bricks(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; short w = butr->xmax-butr->xmin; @@ -1848,7 +1848,7 @@ static char* noisebasis_menu() static void node_texture_buts_proc(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; Tex *tex = (Tex *)node->storage; @@ -1927,7 +1927,7 @@ static void node_texture_buts_proc(uiLayout *layout, PointerRNA *ptr) static void node_texture_buts_image(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; bNodeTree *ntree= ptr->id.data; rctf *butr= &node->butr; @@ -1966,7 +1966,7 @@ static void node_texture_buts_image(uiLayout *layout, PointerRNA *ptr) static void node_texture_buts_output(uiLayout *layout, PointerRNA *ptr) { - uiBlock *block= uiLayoutFreeBlock(layout); + uiBlock *block= uiLayoutAbsoluteBlock(layout); bNode *node= ptr->data; rctf *butr= &node->butr; uiBut *bt; diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c index 72cbacd9b6d..70f3cc955b8 100644 --- a/source/blender/editors/space_sequencer/sequencer_buttons.c +++ b/source/blender/editors/space_sequencer/sequencer_buttons.c @@ -72,7 +72,7 @@ static void sequencer_panel_view_properties(const bContext *C, Panel *pa) { uiBlock *block; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_sequencer_panel_events, NULL); } @@ -82,7 +82,7 @@ static void sequencer_panel_properties(const bContext *C, Panel *pa) { uiBlock *block; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_sequencer_panel_events, NULL); } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 161b73032f5..2ce7da4c073 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -152,8 +152,9 @@ typedef struct { /* is used for both read and write... */ -static void v3d_editvertex_buts(const bContext *C, uiBlock *block, View3D *v3d, Object *ob, float lim) +static void v3d_editvertex_buts(const bContext *C, uiLayout *layout, View3D *v3d, Object *ob, float lim) { + uiBlock *block= (layout)? uiLayoutAbsoluteBlock(layout): NULL; MDeformVert *dvert=NULL; TransformProperties *tfp= v3d->properties_storage; float median[5], ve_median[5]; @@ -497,12 +498,15 @@ static void validate_bonebutton_cb(bContext *C, void *bonev, void *namev) } #endif -static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float lim) +static void v3d_posearmature_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim) { + uiBlock *block= uiLayoutGetBlock(layout); bArmature *arm; bPoseChannel *pchan; Bone *bone= NULL; TransformProperties *tfp= v3d->properties_storage; + PointerRNA pchanptr; + uiLayout *row; arm = ob->data; if (!arm || !ob->pose) return; @@ -516,7 +520,15 @@ static void v3d_posearmature_buts(uiBlock *block, View3D *v3d, Object *ob, float uiDefBut(block, LABEL, 0, "No Bone Active", 0, 240, 100, 20, 0, 0, 0, 0, 0, ""); return; } + else { + row= uiLayoutRow(layout, 0); + RNA_pointer_create(&ob->id, &RNA_PoseChannel, pchan, &pchanptr); + uiItemL(row, "", ICON_BONE_DATA); + uiItemR(row, "", 0, &pchanptr, "name", 0); + } + uiLayoutAbsoluteBlock(layout); + if (pchan->rotmode == ROT_MODE_AXISANGLE) { float quat[4]; /* convert to euler, passing through quats... */ @@ -587,11 +599,14 @@ void validate_editbonebutton_cb(bContext *C, void *bonev, void *namev) WM_event_add_notifier(C, NC_OBJECT|ND_BONE_SELECT, CTX_data_edit_object(C)); // XXX fix } -static void v3d_editarmature_buts(uiBlock *block, View3D *v3d, Object *ob, float lim) +static void v3d_editarmature_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim) { + uiBlock *block= uiLayoutGetBlock(layout); bArmature *arm= ob->data; EditBone *ebone; TransformProperties *tfp= v3d->properties_storage; + uiLayout *row; + PointerRNA eboneptr; ebone= arm->edbo->first; @@ -603,6 +618,13 @@ static void v3d_editarmature_buts(uiBlock *block, View3D *v3d, Object *ob, float if (!ebone) return; + row= uiLayoutRow(layout, 0); + RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &eboneptr); + uiItemL(row, "", ICON_BONE_DATA); + uiItemR(row, "", 0, &eboneptr, "name", 0); + + uiLayoutAbsoluteBlock(layout); + uiDefBut(block, LABEL, 0, "Head:", 0, 210, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); uiDefButF(block, NUM, B_ARMATUREPANEL1, "X:", 0, 190, 100, 19, ebone->head, -lim, lim, 10, 3, "X Location of the head end of the bone"); @@ -630,8 +652,9 @@ static void v3d_editarmature_buts(uiBlock *block, View3D *v3d, Object *ob, float } -static void v3d_editmetaball_buts(uiBlock *block, Object *ob, float lim) +static void v3d_editmetaball_buts(uiLayout *layout, Object *ob, float lim) { + uiBlock *block= uiLayoutAbsoluteBlock(layout); MetaElem *lastelem= NULL; // XXX if(lastelem) { @@ -1013,7 +1036,7 @@ static void view3d_panel_transform_spaces(const bContext *C, Panel *pa) int xco = 20, yco = 70; int index; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockBeginAlign(block); @@ -1095,6 +1118,8 @@ static void view3d_panel_object(const bContext *C, Panel *pa) //uiBut *bt; Object *ob= OBACT; TransformProperties *tfp; + PointerRNA obptr; + uiLayout *col, *row; float lim; if(ob==NULL) return; @@ -1104,9 +1129,6 @@ static void view3d_panel_object(const bContext *C, Panel *pa) v3d->properties_storage= MEM_callocN(sizeof(TransformProperties), "TransformProperties"); tfp= v3d->properties_storage; - block= uiLayoutFreeBlock(pa->layout); - uiBlockSetHandleFunc(block, do_view3d_region_buttons, NULL); - // XXX uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE); if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT)) { @@ -1120,17 +1142,29 @@ static void view3d_panel_object(const bContext *C, Panel *pa) lim= 10000.0f*MAX2(1.0, v3d->grid); + block= uiLayoutGetBlock(pa->layout); + uiBlockSetHandleFunc(block, do_view3d_region_buttons, NULL); + + col= uiLayoutColumn(pa->layout, 0); + row= uiLayoutRow(col, 0); + RNA_id_pointer_create(&ob->id, &obptr); + uiItemL(row, "", ICON_OBJECT_DATA); + uiItemR(row, "", 0, &obptr, "name", 0); + if(ob==obedit) { - if(ob->type==OB_ARMATURE) v3d_editarmature_buts(block, v3d, ob, lim); - if(ob->type==OB_MBALL) v3d_editmetaball_buts(block, ob, lim); - else v3d_editvertex_buts(C, block, v3d, ob, lim); + if(ob->type==OB_ARMATURE) v3d_editarmature_buts(col, v3d, ob, lim); + if(ob->type==OB_MBALL) v3d_editmetaball_buts(col, ob, lim); + else v3d_editvertex_buts(C, col, v3d, ob, lim); } else if(ob->mode & OB_MODE_POSE) { - v3d_posearmature_buts(block, v3d, ob, lim); + v3d_posearmature_buts(col, v3d, ob, lim); } else { BoundBox *bb = NULL; - + + uiLayoutAbsoluteBlock(col); + + block= uiLayoutAbsoluteBlock(col); uiDefBut(block, LABEL, 0, "Location:", 0, 300, 100, 20, 0, 0, 0, 0, 0, ""); uiBlockBeginAlign(block); uiDefButF(block, NUM, B_OBJECTPANEL, "X:", 0, 280, 120, 19, &(ob->loc[0]), -lim, lim, 100, 3, ""); @@ -1307,7 +1341,7 @@ static void view3d_panel_bonesketch_spaces(const bContext *C, Panel *pa) }; - block= uiLayoutFreeBlock(pa->layout); + block= uiLayoutAbsoluteBlock(pa->layout); uiBlockSetHandleFunc(block, do_view3d_region_buttons, NULL); uiBlockBeginAlign(block); diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 0d19a720cdb..a44e3743bb4 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -1964,7 +1964,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) uiBlock *block; int a, xco=0, maxco=0, yco= 0; - block= uiLayoutFreeBlock(layout); + block= uiLayoutAbsoluteBlock(layout); uiBlockSetHandleFunc(block, do_view3d_header_buttons, NULL); if((sa->flag & HEADER_NO_PULLDOWN)==0) From 488c06d1827d5bf5d02a22fcc11a1dfeb50143a7 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 9 Oct 2009 12:15:46 +0000 Subject: [PATCH 051/138] Cessen Request: In Animation Editors, F-Curves for Pose Channel Constraints now include the Pose Channel and Constraint names in the 'owner' part of the name displayed, making it easier to identify which Pose Channel some constraint F-Curve belonged to. e.g. The influence setting for an IK Constraint on bone "Boney" Old Version: Influence (IK) New Version: Influence (Boney : IK) We can experiment with different representations of this later (maybe '>' instead of ':' ?) --- .../editors/animation/anim_ipo_utils.c | 69 +++++++++++++++---- 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 26edf930f0b..1590aa57463 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -35,6 +35,7 @@ #include #include +#include #include "MEM_guardedalloc.h" @@ -92,6 +93,30 @@ int geticon_anim_blocktype(short blocktype) } } +/* helper function for getname_*() - grabs the text within the "" that starts with 'blahblah' + * i.e. for string 'pose["apples"]' with prefix 'pose[', it should grab "apples" + * + * - str: is the entire string to chop + * - prefix: is the part of the string to leave out + * + * Assume that the strings returned must be freed afterwards, and that the inputs will contain + * data we want... + */ +static char *grab_quoted_text (const char *str, const char *prefix) +{ + int prefixLen = strlen(prefix); + char *startMatch, *endMatch; + + /* get the starting point (i.e. where prefix starts, and add prefixLen+1 to it to get be after the first " */ + startMatch= strstr(str, prefix) + prefixLen + 1; + + /* get the end point (i.e. where the next occurance of " is after the starting point) */ + endMatch= strchr(startMatch, '"'); // " NOTE: this comment here is just so that my text editor still shows the functions ok... + + /* return the slice indicated */ + return BLI_strdupn(startMatch, (int)(endMatch-startMatch)); +} + /* Write into "name" buffer, the name of the property (retrieved using RNA from the curve's settings) * WARNING: name buffer we're writing to cannot exceed 256 chars (check anim_channels_defines.c for details) */ @@ -118,7 +143,7 @@ void getname_anim_fcurve(char *name, ID *id, FCurve *fcu) /* try to resolve the path */ if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) { char *structname=NULL, *propname=NULL, *arrayname=NULL, arrayindbuf[16]; - PropertyRNA *nameprop; + short free_structname = 0; /* For now, name will consist of 3 parts: struct-name, property name, array index * There are several options possible: @@ -132,16 +157,34 @@ void getname_anim_fcurve(char *name, ID *id, FCurve *fcu) * hierarchy though, which isn't so clear with option 2. */ - /* for structname, we use a custom name if one is available */ - // xxx we might want an icon from types? - // xxx it is hard to differentiate between object and bone channels then, if ob + bone motion occur together... - nameprop= RNA_struct_name_property(ptr.type); - if (nameprop) { - /* this gets a string which will need to be freed */ - structname= RNA_property_string_get_alloc(&ptr, nameprop, NULL, 0); + /* for structname + * - as base, we use a custom name from the structs if one is available + * - however, if we're showing subdata of bones (probably there will be other exceptions later) + * need to include that info too since it gets confusing otherwise + */ + if (strstr(fcu->rna_path, "pose_channels") && strstr(fcu->rna_path, "constraints")) { + /* perform string 'chopping' to get "Bone Name : Constraint Name" */ + char *pchanName= grab_quoted_text(fcu->rna_path, "pose_channels["); + char *constName= grab_quoted_text(fcu->rna_path, "constraints["); + + /* assemble the string to display in the UI... */ + structname= BLI_sprintfN("%s : %s", pchanName, constName); + free_structname= 1; + + /* free the temp names */ + if (pchanName) MEM_freeN(pchanName); + if (constName) MEM_freeN(constName); + } + else { + PropertyRNA *nameprop= RNA_struct_name_property(ptr.type); + if (nameprop) { + /* this gets a string which will need to be freed */ + structname= RNA_property_string_get_alloc(&ptr, nameprop, NULL, 0); + free_structname= 1; + } + else + structname= (char *)RNA_struct_ui_name(ptr.type); } - else - structname= (char *)RNA_struct_ui_name(ptr.type); /* Property Name is straightforward */ propname= (char *)RNA_property_ui_name(prop); @@ -151,9 +194,9 @@ void getname_anim_fcurve(char *name, ID *id, FCurve *fcu) char c= RNA_property_array_item_char(prop, fcu->array_index); /* we need to write the index to a temp buffer (in py syntax) */ - if(c) sprintf(arrayindbuf, "%c ", c); + if (c) sprintf(arrayindbuf, "%c ", c); else sprintf(arrayindbuf, "[%d]", fcu->array_index); - + arrayname= &arrayindbuf[0]; } else { @@ -166,7 +209,7 @@ void getname_anim_fcurve(char *name, ID *id, FCurve *fcu) BLI_snprintf(name, 128, "%s%s (%s)", arrayname, propname, structname); /* free temp name if nameprop is set */ - if (nameprop) + if (free_structname) MEM_freeN(structname); } else { From 9f7038c5a73d8e73b858a129561d4721481f62e2 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 9 Oct 2009 12:16:58 +0000 Subject: [PATCH 052/138] * Warning fixes for previous commit for Modifier renaming. * Removed some old code (depsgraph) that was already commented out --- source/blender/blenkernel/intern/depsgraph.c | 25 +------------------- source/blender/blenkernel/intern/library.c | 3 ++- source/blender/blenloader/intern/readfile.c | 4 ++-- source/blender/editors/object/object_edit.c | 4 ++-- source/blender/editors/object/object_hook.c | 2 +- 5 files changed, 8 insertions(+), 30 deletions(-) diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index a8cec6070a0..ec054bc47cd 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2391,29 +2391,6 @@ void DAG_pose_sort(Object *ob) ListBase targets = {NULL, NULL}; bConstraintTarget *ct; -#if 0 // XXX old animation system... driver stuff to watch out for - if(con->ipo) { - IpoCurve *icu; - for(icu= con->ipo->curve.first; icu; icu= icu->next) { - /* icu->driver->ob should actually point to ob->proxy if it - * is a proxy, but since it wasn't set correct it older - * files comparing with ob->proxy makes it work for those */ - if(icu->driver && (icu->driver->ob==ob || icu->driver->ob==ob->proxy)) { - bPoseChannel *target= get_pose_channel(ob->pose, icu->driver->name); - if(target) { - node2 = dag_get_node(dag, target); - dag_add_relation(dag, node2, node, 0, "Ipo Driver"); - - /* uncommented this line, results in dependencies - * not being added properly for this constraint, - * what is the purpose of this? - brecht */ - /*cti= NULL;*/ /* trick to get next loop skipped */ - } - } - } - } -#endif // XXX old animation system... driver stuff to watch out for - if (cti && cti->get_constraint_targets) { cti->get_constraint_targets(con, &targets); @@ -2423,7 +2400,7 @@ void DAG_pose_sort(Object *ob) if (target) { node2= dag_get_node(dag, target); dag_add_relation(dag, node2, node, 0, "IK Constraint"); - + if (con->type==CONSTRAINT_TYPE_KINEMATIC) { bKinematicConstraint *data = (bKinematicConstraint *)con->data; bPoseChannel *parchan; diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 0f65be207d9..a79c3472426 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1208,12 +1208,13 @@ static void lib_indirect_test_id(ID *id) int a; - // XXX old animation system! + // XXX old animation system! -------------------------------------- for (strip=ob->nlastrips.first; strip; strip=strip->next){ LIBTAG(strip->object); LIBTAG(strip->act); LIBTAG(strip->ipo); } + // XXX: new animation system needs something like this? for(a=0; atotcol; a++) { LIBTAG(ob->mat[a]); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 49dae2af168..9b4ed4d11a7 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -4096,7 +4096,7 @@ static void direct_link_object(FileData *fd, Object *ob) BLI_addhead(&ob->modifiers, hmd); BLI_remlink(&ob->hooks, hook); - modifier_unique_name(&ob->modifiers, hmd); + modifier_unique_name(&ob->modifiers, (ModifierData*)hmd); MEM_freeN(hook); } @@ -7662,7 +7662,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) BLI_addtail(&ob->modifiers, smd); - modifier_unique_name(&ob->modifiers, smd); + modifier_unique_name(&ob->modifiers, (ModifierData*)smd); } } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 55f95f451d2..ac47556c7f7 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -848,7 +848,7 @@ void special_editmenu(Scene *scene, View3D *v3d) BooleanModifierData *bmd = NULL; bmd = (BooleanModifierData *)modifier_new(eModifierType_Boolean); BLI_addtail(&ob->modifiers, bmd); - modifier_unique_name(&ob->modifiers, bmd); + modifier_unique_name(&ob->modifiers, (ModifierData*)bmd); bmd->object = base_select->object; bmd->modifier.mode |= eModifierMode_Realtime; switch(nr){ @@ -981,7 +981,7 @@ static void object_flip_subdivison_particles(Scene *scene, Object *ob, int *set, SubsurfModifierData *smd = (SubsurfModifierData*) modifier_new(eModifierType_Subsurf); BLI_addtail(&ob->modifiers, smd); - modifier_unique_name(&ob->modifiers, smd); + modifier_unique_name(&ob->modifiers, (ModifierData*)smd); if (level!=-1) { smd->levels = level; diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 63182e943bb..4643b875872 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -480,7 +480,7 @@ void add_hook(Scene *scene, View3D *v3d, int mode) hmd = (HookModifierData*) modifier_new(eModifierType_Hook); BLI_insertlinkbefore(&obedit->modifiers, md, hmd); sprintf(hmd->modifier.name, "Hook-%s", ob->id.name+2); - modifier_unique_name(&obedit->modifiers, hmd); + modifier_unique_name(&obedit->modifiers, (ModifierData*)hmd); } else if (hmd->indexar) MEM_freeN(hmd->indexar); /* reassign, hook was set */ From 2cf7d4867d4f6651fa54c3824f5e9f8f8a3e3770 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 9 Oct 2009 12:18:32 +0000 Subject: [PATCH 053/138] (Untested) String Replacement Function in blenlib Currently this hasn't been tested yet, but committing this first before I potentially use it for fixing RNA-paths... --- source/blender/blenlib/BLI_string.h | 12 +++++ source/blender/blenlib/intern/string.c | 71 ++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h index bf93dc19cc5..53563f85eb9 100644 --- a/source/blender/blenlib/BLI_string.h +++ b/source/blender/blenlib/BLI_string.h @@ -68,6 +68,18 @@ char *BLI_strdupn(const char *str, int len); */ char *BLI_strncpy(char *dst, const char *src, int maxncpy); + /** + * Returns a copy of the cstring @a str into a newly mallocN'd + * string with all instances of oldText replaced with newText, + * and returns it. + * + * @param str The string to replace occurances of oldText in + * @param oldText The text in the string to find and replace + * @param newText The text in the string to find and replace + * @retval Returns the duplicated string + */ +char *BLI_replacestr(char *str, const char *oldText, const char *newText); + /* * Replacement for snprintf */ diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index 4cd04aa232c..de4b53cbd93 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -100,6 +100,77 @@ char *BLI_sprintfN(const char *format, ...) return n; } +/* Replaces all occurances of oldText with newText in str, returning a new string that doesn't + * contain the 'replaced' occurances. + */ +// A rather wasteful string-replacement utility, though this shall do for now... +// Feel free to replace this with an even safe + nicer alternative +char *BLI_replacestr(char *str, const char *oldText, const char *newText) +{ + DynStr *ds= NULL; + int lenOld= strlen(oldText); + char *match; + + /* sanity checks */ + if ((str == NULL) || (str[0]==0)) + return NULL; + else if ((oldText == NULL) || (newText == NULL) || (oldText[0]==0)) + return BLI_strdup(str); + + /* while we can still find a match for the old substring that we're searching for, + * keep dicing and replacing + */ + while ( (match = strstr(str, oldText)) ) { + /* the assembly buffer only gets created when we actually need to rebuild the string */ + if (ds == NULL) + ds= BLI_dynstr_new(); + + /* if the match position does not match the current position in the string, + * copy the text up to this position and advance the current position in the string + */ + if (str != match) { + /* replace the token at the 'match' position with \0 so that the copied string will be ok, + * add the segment of the string from str to match to the buffer, then restore the value at match + */ + match[0]= 0; + BLI_dynstr_append(ds, str); + match[0]= oldText[0]; + + /* now our current position should be set on the start of the match */ + str= match; + } + + /* add the replacement text to the accumulation buffer */ + BLI_dynstr_append(ds, newText); + + /* advance the current position of the string up to the end of the replaced segment */ + str += lenOld; + } + + /* finish off and return a new string that has had all occurances of */ + if (ds) { + char *newStr; + + /* add what's left of the string to the assembly buffer + * - we've been adjusting str to point at the end of the replaced segments + */ + if (str != NULL) + BLI_dynstr_append(ds, str); + + /* convert to new c-string (MEM_malloc'd), and free the buffer */ + newStr= BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return newStr; + } + else { + /* just create a new copy of the entire string - we avoid going through the assembly buffer + * for what should be a bit more efficiency... + */ + return BLI_strdup(str); + } +} + int BLI_streq(const char *a, const char *b) { return (strcmp(a, b)==0); From 3d771d88d85486800c9a4eae5b596215e816141d Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 9 Oct 2009 12:34:37 +0000 Subject: [PATCH 054/138] wm menu freeing was using freed memory, bone-parent names were being set to "" on menu draw WHY??? - r23247, you know who you are ;) --- source/blender/editors/space_view3d/view3d_buttons.c | 1 - source/blender/windowmanager/intern/wm.c | 12 ++++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 2ce7da4c073..b5a0ca079bc 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1135,7 +1135,6 @@ static void view3d_panel_object(const bContext *C, Panel *pa) } else { if((ob->mode & OB_MODE_PARTICLE_EDIT)==0) { - strcpy(ob->parsubstr, ""); uiBlockEndAlign(block); } } diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index dbb8fc400c0..5b7f892592b 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -162,13 +162,17 @@ void WM_menutype_freelink(MenuType* mt) void WM_menutype_free(void) { - MenuType* mt; + MenuType* mt= menutypes.first, *mt_next; - for(mt= menutypes.first; mt; mt= mt->next) { - if(mt->ext.free) { + while(mt) { + mt_next= mt->next; + + if(mt->ext.free) mt->ext.free(mt->ext.data); - } + WM_menutype_freelink(mt); + + mt= mt_next; } } From ae6c08ac5e7009dca591c39569a16802664dd0c4 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Fri, 9 Oct 2009 12:47:25 +0000 Subject: [PATCH 055/138] Wrong Tooltip for Continuous Grab. --- release/scripts/ui/space_userpref.py | 2 +- source/blender/makesrna/intern/rna_userdef.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py index 27c826b133b..7af8766e256 100644 --- a/release/scripts/ui/space_userpref.py +++ b/release/scripts/ui/space_userpref.py @@ -418,7 +418,7 @@ class USERPREF_PT_input(bpy.types.Panel): sub1 = sub.column() sub1.enabled = (view.select_mouse == 'RIGHT') sub1.itemR(view, "emulate_3_button_mouse") - sub.itemR(view, "continuous_mouse", text="Continuous Grab") + sub.itemR(view, "continuous_mouse") sub.itemL(text="Select With:") sub.row().itemR(view, "select_mouse", expand=True) diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 3e3ed669e02..f8135f32eda 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -1657,7 +1657,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) prop= RNA_def_property(srna, "continuous_mouse", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_CONTINUOUS_MOUSE); - RNA_def_property_ui_text(prop, "Contents Follow Opening Direction", "Otherwise menus, etc will always be top to bottom, left to right, no matter opening direction."); + RNA_def_property_ui_text(prop, "Continuous Grab", "Experimental option to allow moving the mouse outside the view (Linux only at the moment)"); prop= RNA_def_property(srna, "global_pivot", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_LOCKAROUND); From ca3e77813446a8fbdd654dff1e4f5739f462543b Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Fri, 9 Oct 2009 12:48:28 +0000 Subject: [PATCH 056/138] Cocoa port : - Fullscreen mode is back! - Cleaner fix for tablet events handling --- intern/ghost/intern/GHOST_SystemCocoa.h | 3 +- intern/ghost/intern/GHOST_SystemCocoa.mm | 310 ++++-------------- intern/ghost/intern/GHOST_WindowCocoa.h | 24 +- intern/ghost/intern/GHOST_WindowCocoa.mm | 382 ++++++++--------------- 4 files changed, 206 insertions(+), 513 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.h b/intern/ghost/intern/GHOST_SystemCocoa.h index eab5a5b28aa..ee7f9d8ed37 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.h +++ b/intern/ghost/intern/GHOST_SystemCocoa.h @@ -210,9 +210,10 @@ protected: /** * Handles a tablet event. * @param eventPtr An NSEvent pointer (casted to void* to enable compilation in standard C++) + * @param eventType The type of the event. It needs to be passed separately as it can be either directly in the event type, or as a subtype if combined with a mouse button event * @return Indication whether the event was handled. */ - GHOST_TSuccess handleTabletEvent(void *eventPtr); + GHOST_TSuccess handleTabletEvent(void *eventPtr, short eventType); /** * Handles a mouse event. diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 7f98f67a1ba..481dd705265 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -51,43 +51,6 @@ #pragma mark KeyMap, mouse converters -//TODO: remove (kept as reminder to implement window events) -/* -const EventTypeSpec kEvents[] = -{ - { kEventClassAppleEvent, kEventAppleEvent }, - -// { kEventClassApplication, kEventAppActivated }, -// { kEventClassApplication, kEventAppDeactivated }, - - { kEventClassKeyboard, kEventRawKeyDown }, - { kEventClassKeyboard, kEventRawKeyRepeat }, - { kEventClassKeyboard, kEventRawKeyUp }, - { kEventClassKeyboard, kEventRawKeyModifiersChanged }, - - { kEventClassMouse, kEventMouseDown }, - { kEventClassMouse, kEventMouseUp }, - { kEventClassMouse, kEventMouseMoved }, - { kEventClassMouse, kEventMouseDragged }, - { kEventClassMouse, kEventMouseWheelMoved }, - - { kEventClassWindow, kEventWindowClickZoomRgn } , // for new zoom behaviour - { kEventClassWindow, kEventWindowZoom }, // for new zoom behaviour - { kEventClassWindow, kEventWindowExpand } , // for new zoom behaviour - { kEventClassWindow, kEventWindowExpandAll }, // for new zoom behaviour - - { kEventClassWindow, kEventWindowClose }, - { kEventClassWindow, kEventWindowActivated }, - { kEventClassWindow, kEventWindowDeactivated }, - { kEventClassWindow, kEventWindowUpdate }, - { kEventClassWindow, kEventWindowBoundsChanged }, - - { kEventClassBlender, kEventBlenderNdofAxis }, - { kEventClassBlender, kEventBlenderNdofButtons } - - - -};*/ /* Keycodes from Carbon include file */ /* @@ -701,25 +664,6 @@ GHOST_TSuccess GHOST_SystemCocoa::init() } [pool drain]; - - /* - * Initialize the cursor to the standard arrow shape (so that we can change it later on). - * This initializes the cursor's visibility counter to 0. - */ - /*::InitCursor(); - - MenuRef windMenu; - ::CreateStandardWindowMenu(0, &windMenu); - ::InsertMenu(windMenu, 0); - ::DrawMenuBar(); - - ::InstallApplicationEventHandler(sEventHandlerProc, GetEventTypeCount(kEvents), kEvents, this, &m_handler); - - ::AEInstallEventHandler(kCoreEventClass, kAEOpenApplication, sAEHandlerLaunch, (SInt32) this, false); - ::AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, sAEHandlerOpenDocs, (SInt32) this, false); - ::AEInstallEventHandler(kCoreEventClass, kAEPrintDocuments, sAEHandlerPrintDocs, (SInt32) this, false); - ::AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, sAEHandlerQuit, (SInt32) this, false); - */ } return success; } @@ -789,6 +733,13 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; GHOST_IWindow* window = 0; + //First check if we are in fullscreen mode + //If so, exit it before creating a new window + window = m_windowManager->getActiveWindow(); + if (window && (window->getState() == GHOST_kWindowStateFullScreen)) + window->setState(GHOST_kWindowStateNormal); + window = NULL; + //Get the available rect for including window contents NSRect frame = [[NSScreen mainScreen] visibleFrame]; NSRect contentRect = [NSWindow contentRectForFrameRect:frame @@ -826,27 +777,18 @@ GHOST_IWindow* GHOST_SystemCocoa::createWindow( GHOST_TSuccess GHOST_SystemCocoa::beginFullScreen(const GHOST_DisplaySetting& setting, GHOST_IWindow** window, const bool stereoVisual) { - GHOST_TSuccess success = GHOST_kFailure; + GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow(); - //TODO: update this method - // need yo make this Carbon all on 10.5 for fullscreen to work correctly - CGCaptureAllDisplays(); + *window = currentWindow; - success = GHOST_System::beginFullScreen( setting, window, stereoVisual); - - if( success != GHOST_kSuccess ) { - // fullscreen failed for other reasons, release - CGReleaseAllDisplays(); - } - - return success; + return currentWindow->setState(GHOST_kWindowStateFullScreen); } GHOST_TSuccess GHOST_SystemCocoa::endFullScreen(void) { - //TODO: update this method - CGReleaseAllDisplays(); - return GHOST_System::endFullScreen(); + GHOST_IWindow* currentWindow = m_windowManager->getActiveWindow(); + + return currentWindow->setState(GHOST_kWindowStateNormal); } @@ -936,8 +878,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) anyProcessed = true; } - //TODO: check fullscreen redrawing issues - if (getFullScreen()) { + if (getFullScreen()) { // Check if the full-screen window is dirty GHOST_IWindow* window = m_windowManager->getFullScreenWindow(); if (((GHOST_WindowCarbon*)window)->getFullScreenDirty()) { @@ -987,7 +928,7 @@ bool GHOST_SystemCocoa::processEvents(bool waitForEvent) case NSTabletPoint: case NSTabletProximity: - handleTabletEvent(event); + handleTabletEvent(event,[event type]); break; /* Trackpad features, will need OS X 10.6 for implementation @@ -1028,8 +969,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, if (!validWindow(window)) { return GHOST_kFailure; } - - //if (!getFullScreen()) { switch(eventType) { case GHOST_kEventWindowClose: @@ -1045,7 +984,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowDeactivate, window) ); break; case GHOST_kEventWindowUpdate: - //if (getFullScreen()) GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen update event\n"); pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowUpdate, window) ); break; case GHOST_kEventWindowSize: @@ -1059,12 +997,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleWindowEvent(GHOST_TEventType eventType, return GHOST_kFailure; break; } -// } - //else { - //window = (GHOST_WindowCarbon*) m_windowManager->getFullScreenWindow(); - //GHOST_PRINT("GHOST_SystemCarbon::handleWindowEvent(): full-screen window event, " << window << "\n"); - //::RemoveEventFromQueue(::GetMainEventQueue(), event); - //} return GHOST_kSuccess; } @@ -1073,6 +1005,13 @@ GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest() //Check open windows if some changes are not saved if (m_windowManager->getAnyModifiedState()) { + //First check if we are in fullscreen mode + //If so, exit it before creating a new window + GHOST_IWindow *window = m_windowManager->getActiveWindow(); + if (window && (window->getState() == GHOST_kWindowStateFullScreen)) + window->setState(GHOST_kWindowStateNormal); + window = NULL; + int shouldQuit = NSRunAlertPanel(@"Exit Blender", @"Some changes have not been saved. Do you really want to quit ?", @"Cancel", @"Quit anyway", nil); if (shouldQuit == NSAlertAlternateReturn) @@ -1090,35 +1029,13 @@ GHOST_TUns8 GHOST_SystemCocoa::handleQuitRequest() } -GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr) +GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventType) { NSEvent *event = (NSEvent *)eventPtr; GHOST_IWindow* window = m_windowManager->getActiveWindow(); GHOST_TabletData& ct=((GHOST_WindowCocoa*)window)->GetCocoaTabletData(); - NSUInteger tabletEvent; - //Handle tablet events combined with mouse events - @try { - switch ([event subtype]) { - case NX_SUBTYPE_TABLET_POINT: - tabletEvent = NSTabletPoint; - break; - case NX_SUBTYPE_TABLET_PROXIMITY: - tabletEvent = NSTabletProximity; - break; - - default: - tabletEvent = [event type]; - break; - } - } - @catch (NSException * e) { - //FIXME: check why we get such exceptions when using a tablet - return GHOST_kFailure; - } - - - switch (tabletEvent) { + switch (eventType) { case NSTabletPoint: ct.Pressure = [event tangentialPressure]; ct.Xtilt = [event tilt].x; @@ -1175,20 +1092,53 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) case NSRightMouseDown: case NSOtherMouseDown: pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonDown, window, convertButton([event buttonNumber]))); - handleTabletEvent(eventPtr); + //Handle tablet events combined with mouse events + switch ([event subtype]) { + case NX_SUBTYPE_TABLET_POINT: + handleTabletEvent(eventPtr, NSTabletPoint); + break; + case NX_SUBTYPE_TABLET_PROXIMITY: + handleTabletEvent(eventPtr, NSTabletProximity); + break; + default: + //No tablet event included : do nothing + break; + } break; case NSLeftMouseUp: case NSRightMouseUp: case NSOtherMouseUp: pushEvent(new GHOST_EventButton([event timestamp], GHOST_kEventButtonUp, window, convertButton([event buttonNumber]))); - handleTabletEvent(eventPtr); + //Handle tablet events combined with mouse events + switch ([event subtype]) { + case NX_SUBTYPE_TABLET_POINT: + handleTabletEvent(eventPtr, NSTabletPoint); + break; + case NX_SUBTYPE_TABLET_PROXIMITY: + handleTabletEvent(eventPtr, NSTabletProximity); + break; + default: + //No tablet event included : do nothing + break; + } break; case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: - handleTabletEvent(eventPtr); + //Handle tablet events combined with mouse events + switch ([event subtype]) { + case NX_SUBTYPE_TABLET_POINT: + handleTabletEvent(eventPtr, NSTabletPoint); + break; + case NX_SUBTYPE_TABLET_PROXIMITY: + handleTabletEvent(eventPtr, NSTabletProximity); + break; + default: + //No tablet event included : do nothing + break; + } case NSMouseMoved: { NSPoint mousePos = [event locationInWindow]; @@ -1227,6 +1177,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) * the window go away and we still get an HKey up. */ if (!window) { + printf("\nW failure"); return GHOST_kFailure; } @@ -1246,7 +1197,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) if ((keyCode == GHOST_kKeyQ) && (m_modifierMask & NSCommandKeyMask)) break; //Cmd-Q is directly handled by Cocoa - + if ([event type] == NSKeyDown) { pushEvent( new GHOST_EventKey([event timestamp], GHOST_kEventKeyDown, window, keyCode, ascii) ); //printf("\nKey pressed keyCode=%u ascii=%i %c",keyCode,ascii,ascii); @@ -1282,143 +1233,6 @@ GHOST_TSuccess GHOST_SystemCocoa::handleKeyEvent(void *eventPtr) } -/* System wide mouse clicks are handled directly through systematic event forwarding to Cocoa -bool GHOST_SystemCarbon::handleMouseDown(void *eventPtr) -{ - NSEvent *event = (NSEvent *)eventPtr; - WindowPtr window; - short part; - BitMap screenBits; - bool handled = true; - GHOST_WindowCarbon* ghostWindow; - Point mousePos = {0 , 0}; - - ::GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePos); - - part = ::FindWindow(mousePos, &window); - ghostWindow = (GHOST_WindowCarbon*) ::GetWRefCon(window); - - switch (part) { - case inMenuBar: - handleMenuCommand(::MenuSelect(mousePos)); - break; - - case inDrag: - // * - // * The DragWindow() routine creates a lot of kEventWindowBoundsChanged - // * events. By setting m_ignoreWindowSizedMessages these are suppressed. - // * @see GHOST_SystemCarbon::handleWindowEvent(EventRef event) - // * - // even worse: scale window also generates a load of events, and nothing - // is handled (read: client's event proc called) until you release mouse (ton) - - GHOST_ASSERT(validWindow(ghostWindow), "GHOST_SystemCarbon::handleMouseDown: invalid window"); - m_ignoreWindowSizedMessages = true; - ::DragWindow(window, mousePos, &GetQDGlobalsScreenBits(&screenBits)->bounds); - m_ignoreWindowSizedMessages = false; - - pushEvent( new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowMove, ghostWindow) ); - - break; - - case inContent: - if (window != ::FrontWindow()) { - ::SelectWindow(window); - // - // * We add a mouse down event on the newly actived window - // * - //GHOST_PRINT("GHOST_SystemCarbon::handleMouseDown(): adding mouse down event, " << ghostWindow << "\n"); - EventMouseButton button; - ::GetEventParameter(event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(button), NULL, &button); - pushEvent(new GHOST_EventButton(getMilliSeconds(), GHOST_kEventButtonDown, ghostWindow, convertButton(button))); - } else { - handled = false; - } - break; - - case inGoAway: - GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); - if (::TrackGoAway(window, mousePos)) - { - // todo: add option-close, because itÿs in the HIG - // if (event.modifiers & optionKey) { - // Close the clean documents, others will be confirmed one by one. - //} - // else { - pushEvent(new GHOST_Event(getMilliSeconds(), GHOST_kEventWindowClose, ghostWindow)); - //} - } - break; - - case inGrow: - GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); - ::ResizeWindow(window, mousePos, NULL, NULL); - break; - - case inZoomIn: - case inZoomOut: - GHOST_ASSERT(ghostWindow, "GHOST_SystemCarbon::handleMouseEvent: ghostWindow==0"); - if (::TrackBox(window, mousePos, part)) { - int macState; - - macState = ghostWindow->getMac_windowState(); - if ( macState== 0) - ::ZoomWindow(window, part, true); - else - if (macState == 2) { // always ok - ::ZoomWindow(window, part, true); - ghostWindow->setMac_windowState(1); - } else { // need to force size again - // GHOST_TUns32 scr_x,scr_y; //unused - Rect outAvailableRect; - - ghostWindow->setMac_windowState(2); - ::GetAvailableWindowPositioningBounds ( GetMainDevice(), &outAvailableRect); - - //this->getMainDisplayDimensions(scr_x,scr_y); - ::SizeWindow (window, outAvailableRect.right-outAvailableRect.left,outAvailableRect.bottom-outAvailableRect.top-1,false); - ::MoveWindow (window, outAvailableRect.left, outAvailableRect.top,true); - } - - } - break; - - default: - handled = false; - break; - } - - return handled; -} - - -bool GHOST_SystemCarbon::handleMenuCommand(GHOST_TInt32 menuResult) -{ - short menuID; - short menuItem; - UInt32 command; - bool handled; - OSErr err; - - menuID = HiWord(menuResult); - menuItem = LoWord(menuResult); - - err = ::GetMenuItemCommandID(::GetMenuHandle(menuID), menuItem, &command); - - handled = false; - - if (err || command == 0) { - } - else { - switch(command) { - } - } - - ::HiliteMenu(0); - return handled; -}*/ - - #pragma mark Clipboard get/set diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 5ff205d964f..8c2919d1ce2 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -70,7 +70,7 @@ public: * @param stereoVisual Stereo visual for quad buffered stereo. */ GHOST_WindowCocoa( - const GHOST_SystemCocoa *systemCocoa, + GHOST_SystemCocoa *systemCocoa, const STR_String& title, GHOST_TInt32 left, GHOST_TInt32 top, @@ -204,16 +204,6 @@ public: virtual void loadCursor(bool visible, GHOST_TStandardCursor cursor) const; - /** - * Returns the dirty state of the window when in full-screen mode. - * @return Whether it is dirty. - */ - virtual bool getFullScreenDirty(); - - /* accessor for fullscreen window */ - /*virtual void setMac_windowState(short value); - virtual short getMac_windowState();*/ - const GHOST_TabletData* GetTabletData() { return &m_tablet; } @@ -270,19 +260,13 @@ protected: /** The opgnGL drawing context */ NSOpenGLContext *m_openGLContext; - //CGrafPtr m_grafPtr; - //AGLContext m_aglCtx; - - /** The first created OpenGL context (for sharing display lists) */ - //static AGLContext s_firstaglCtx; - + /** The mother SystemCocoa class to send events */ + GHOST_SystemCocoa *m_systemCocoa; + NSCursor* m_customCursor; GHOST_TabletData m_tablet; - /** When running in full-screen this tells whether to refresh the window. */ - bool m_fullScreenDirty; - /** * The width/height of the size rectangle in the lower right corner of a * Mac/Carbon window. This is also the height of the gutter area. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index a185aa036b1..f4c9172c668 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -32,57 +32,20 @@ #include "GHOST_WindowCocoa.h" #include "GHOST_SystemCocoa.h" #include "GHOST_Debug.h" -/* -AGLContext GHOST_WindowCocoa::s_firstaglCtx = NULL; -#ifdef GHOST_DRAW_CARBON_GUTTER -const GHOST_TInt32 GHOST_WindowCocoa::s_sizeRectSize = 16; -#endif //GHOST_DRAW_CARBON_GUTTER -static const GLint sPreferredFormatWindow[8] = { -AGL_RGBA, -AGL_DOUBLEBUFFER, -AGL_ACCELERATED, -AGL_DEPTH_SIZE, 32, -AGL_NONE, + +// Pixel Format Attributes for the windowed NSOpenGLContext +static const NSOpenGLPixelFormatAttribute pixelFormatAttrsWindow[] = +{ + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAccelerated, + NSOpenGLPFAAllowOfflineRenderers, // NOTE: Needed to connect to secondary GPUs + NSOpenGLPFADepthSize, 32, + 0 }; -static const GLint sPreferredFormatFullScreen[9] = { -AGL_RGBA, -AGL_DOUBLEBUFFER, -AGL_ACCELERATED, -AGL_FULLSCREEN, -AGL_DEPTH_SIZE, 32, -AGL_NONE, -}; - - - -WindowRef ugly_hack=NULL; - -const EventTypeSpec kWEvents[] = { - { kEventClassWindow, kEventWindowZoom }, // for new zoom behaviour -}; - -static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, void* userData) { - WindowRef mywindow; - GHOST_WindowCocoa *ghost_window; - OSStatus err; - int theState; - - if (::GetEventKind(event) == kEventWindowZoom) { - err = ::GetEventParameter (event,kEventParamDirectObject,typeWindowRef,NULL,sizeof(mywindow),NULL, &mywindow); - ghost_window = (GHOST_WindowCocoa *) GetWRefCon(mywindow); - theState = ghost_window->getMac_windowState(); - if (theState == 1) - ghost_window->setMac_windowState(2); - else if (theState == 2) - ghost_window->setMac_windowState(1); - - } - return eventNotHandledErr; -}*/ - #pragma mark Cocoa delegate object + @interface CocoaWindowDelegate : NSObject { GHOST_SystemCocoa *systemCocoa; @@ -116,7 +79,10 @@ static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, - (void)windowDidResignKey:(NSNotification *)notification { - systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow); + //The window is no more key when its own view becomes fullscreen + //but ghost doesn't know the view/window difference, so hide this fact + if (associatedWindow->getState() != GHOST_kWindowStateFullScreen) + systemCocoa->handleWindowEvent(GHOST_kEventWindowDeactivate, associatedWindow); } - (void)windowDidUpdate:(NSNotification *)notification @@ -159,7 +125,7 @@ static OSStatus myWEventHandlerProc(EventHandlerCallRef handler, EventRef event, #pragma mark initialization / finalization GHOST_WindowCocoa::GHOST_WindowCocoa( - const GHOST_SystemCocoa *systemCocoa, + GHOST_SystemCocoa *systemCocoa, const STR_String& title, GHOST_TInt32 left, GHOST_TInt32 top, @@ -170,136 +136,55 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( const bool stereoVisual ) : GHOST_Window(title, left, top, width, height, state, GHOST_kDrawingContextTypeNone), - m_customCursor(0), - m_fullScreenDirty(false) + m_customCursor(0) { + m_systemCocoa = systemCocoa; + m_fullScreen = false; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - //fprintf(stderr," main screen top %i left %i height %i width %i\n", top, left, height, width); - /* - if (state >= GHOST_kWindowState8Normal ) { - if(state == GHOST_kWindowState8Normal) state= GHOST_kWindowStateNormal; - else if(state == GHOST_kWindowState8Maximized) state= GHOST_kWindowStateMaximized; - else if(state == GHOST_kWindowState8Minimized) state= GHOST_kWindowStateMinimized; - else if(state == GHOST_kWindowState8FullScreen) state= GHOST_kWindowStateFullScreen; - - // state = state - 8; this was the simple version of above code, doesnt work in gcc 4.0 - - setMac_windowState(1); - } else - setMac_windowState(0); -*/ - if (state != GHOST_kWindowStateFullScreen) { - - //Creates the window - NSRect rect; - - rect.origin.x = left; - rect.origin.y = top; - rect.size.width = width; - rect.size.height = height; - - m_window = [[NSWindow alloc] initWithContentRect:rect - styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask - backing:NSBackingStoreBuffered defer:NO]; - if (m_window == nil) { - [pool drain]; - return; - } - - [m_window setTitle:[NSString stringWithUTF8String:title]]; - - - //Creates the OpenGL View inside the window - NSOpenGLPixelFormatAttribute attributes[] = - { - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAccelerated, - NSOpenGLPFAAllowOfflineRenderers, // NOTE: Needed to connect to secondary GPUs - NSOpenGLPFADepthSize, 32, - 0 - }; - - NSOpenGLPixelFormat *pixelFormat = - [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - - m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect - pixelFormat:pixelFormat]; - - [pixelFormat release]; - - m_openGLContext = [m_openGLView openGLContext]; - - [m_window setContentView:m_openGLView]; - [m_window setInitialFirstResponder:m_openGLView]; - - [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window - - [m_window makeKeyAndOrderFront:nil]; - - setDrawingContextType(type); - updateDrawingContext(); - activateDrawingContext(); - - // Boolean visible = (state == GHOST_kWindowStateNormal) || (state == GHOST_kWindowStateMaximized); /*unused*/ - /*gen2mac(title, title255); - - - err = ::CreateNewWindow( kDocumentWindowClass, - kWindowStandardDocumentAttributes+kWindowLiveResizeAttribute, - &bnds, - &m_windowRef); - - if ( err != noErr) { - fprintf(stderr," error creating window %i \n",(int)err); - } else { + + //Creates the window + NSRect rect; + + rect.origin.x = left; + rect.origin.y = top; + rect.size.width = width; + rect.size.height = height; + + m_window = [[NSWindow alloc] initWithContentRect:rect + styleMask:NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask + backing:NSBackingStoreBuffered defer:NO]; + if (m_window == nil) { + [pool drain]; + return; + } + + [m_window setTitle:[NSString stringWithUTF8String:title]]; + - ::SetWRefCon(m_windowRef,(SInt32)this); - setTitle(title); - err = InstallWindowEventHandler (m_windowRef, myWEventHandlerProc, GetEventTypeCount(kWEvents), kWEvents,NULL,NULL); - if ( err != noErr) { - fprintf(stderr," error creating handler %i \n",(int)err); - } else { - // ::TransitionWindow (m_windowRef,kWindowZoomTransitionEffect,kWindowShowTransitionAction,NULL); - ::ShowWindow(m_windowRef); - ::MoveWindow (m_windowRef, left, top,true); - - } - } - if (m_windowRef) { - m_grafPtr = ::GetWindowPort(m_windowRef); - setDrawingContextType(type); - updateDrawingContext(); - activateDrawingContext(); - } - if(ugly_hack==NULL) { - ugly_hack= m_windowRef; - // when started from commandline, window remains in the back... also for play anim - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - SetFrontProcess(&psn); - }*/ - } - else { - /* - Rect bnds = { top, left, top+height, left+width }; - gen2mac("", title255); - m_windowRef = ::NewCWindow( - nil, // Storage - &bnds, // Bounding rectangle of the window - title255, // Title of the window - 0, // Window initially visible - plainDBox, // procID - (WindowRef)-1L, // Put window before all other windows - 0, // Window has minimize box - (SInt32)this); // Store a pointer to the class in the refCon - */ - //GHOST_PRINT("GHOST_WindowCocoa::GHOST_WindowCocoa(): creating full-screen OpenGL context\n"); - setDrawingContextType(GHOST_kDrawingContextTypeOpenGL); - installDrawingContext(GHOST_kDrawingContextTypeOpenGL); - updateDrawingContext(); - activateDrawingContext(); - } + //Creates the OpenGL View inside the window + NSOpenGLPixelFormat *pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttrsWindow]; + + m_openGLView = [[CocoaOpenGLView alloc] initWithFrame:rect + pixelFormat:pixelFormat]; + + [pixelFormat release]; + + m_openGLContext = [m_openGLView openGLContext]; + + [m_window setContentView:m_openGLView]; + [m_window setInitialFirstResponder:m_openGLView]; + + [m_window setReleasedWhenClosed:NO]; //To avoid bad pointer exception in case of user closing the window + + [m_window makeKeyAndOrderFront:nil]; + + setDrawingContextType(type); + updateDrawingContext(); + activateDrawingContext(); + m_tablet.Active = GHOST_kTabletModeNone; CocoaWindowDelegate *windowDelegate = [[CocoaWindowDelegate alloc] init]; @@ -308,6 +193,9 @@ GHOST_WindowCocoa::GHOST_WindowCocoa( [m_window setAcceptsMouseMovedEvents:YES]; + if (state == GHOST_kWindowStateFullScreen) + setState(GHOST_kWindowStateFullScreen); + [pool drain]; } @@ -401,19 +289,30 @@ void GHOST_WindowCocoa::getClientBounds(GHOST_Rect& bounds) const GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getClientBounds(): window invalid") NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSRect screenSize = [[m_window screen] visibleFrame]; - - //Max window contents as screen size (excluding title bar...) - NSRect contentRect = [NSWindow contentRectForFrameRect:screenSize - styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)]; - - rect = [m_window contentRectForFrameRect:[m_window frame]]; - - bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); - bounds.m_l = rect.origin.x -contentRect.origin.x; - bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; - bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); + if (!m_fullScreen) + { + NSRect screenSize = [[m_window screen] visibleFrame]; + + //Max window contents as screen size (excluding title bar...) + NSRect contentRect = [NSWindow contentRectForFrameRect:screenSize + styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask)]; + + rect = [m_window contentRectForFrameRect:[m_window frame]]; + + bounds.m_b = contentRect.size.height - (rect.origin.y -contentRect.origin.y); + bounds.m_l = rect.origin.x -contentRect.origin.x; + bounds.m_r = rect.origin.x-contentRect.origin.x + rect.size.width; + bounds.m_t = contentRect.size.height - (rect.origin.y + rect.size.height -contentRect.origin.y); + } + else { + NSRect screenSize = [[m_window screen] frame]; + + bounds.m_b = screenSize.origin.y + screenSize.size.height; + bounds.m_l = screenSize.origin.x; + bounds.m_r = screenSize.origin.x + screenSize.size.width; + bounds.m_t = screenSize.origin.y; + } [pool drain]; } @@ -469,7 +368,10 @@ GHOST_TWindowState GHOST_WindowCocoa::getState() const GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::getState(): window invalid") NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; GHOST_TWindowState state; - if ([m_window isMiniaturized]) { + if (m_fullScreen) { + state = GHOST_kWindowStateFullScreen; + } + else if ([m_window isMiniaturized]) { state = GHOST_kWindowStateMinimized; } else if ([m_window isZoomed]) { @@ -521,15 +423,50 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::setState(): window invalid") switch (state) { - case GHOST_kWindowStateMinimized: + case GHOST_kWindowStateMinimized: [m_window miniaturize:nil]; break; - case GHOST_kWindowStateMaximized: + case GHOST_kWindowStateMaximized: [m_window zoom:nil]; break; - case GHOST_kWindowStateNormal: + + case GHOST_kWindowStateFullScreen: + if (!m_fullScreen) + { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + //This status change needs to be done before Cocoa call to enter fullscreen mode + //to give window delegate hint not to forward its deactivation to ghost wm that doesn't know view/window difference + m_fullScreen = true; + + //Only 10.6 API will enable to manage several display in fullscreen mode, and topmenu autoshow + [m_openGLView enterFullScreenMode:[m_window screen] withOptions:nil]; + + //Tell WM of view new size + m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); + + [pool drain]; + } + break; + case GHOST_kWindowStateNormal: default: - if ([m_window isMiniaturized]) + if (m_fullScreen) + { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + m_fullScreen = false; + + //Exit fullscreen + [m_openGLView exitFullScreenModeWithOptions:nil]; + + [m_window makeKeyAndOrderFront:nil]; + [m_window makeFirstResponder:m_openGLView]; + + //Tell WM of view new size + m_systemCocoa->handleWindowEvent(GHOST_kEventWindowSize, this); + + [pool drain]; + } + else if ([m_window isMiniaturized]) [m_window deminiaturize:nil]; else if ([m_window isZoomed]) [m_window zoom:nil]; @@ -540,8 +477,11 @@ GHOST_TSuccess GHOST_WindowCocoa::setState(GHOST_TWindowState state) GHOST_TSuccess GHOST_WindowCocoa::setModifiedState(bool isUnsavedChanges) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [m_window setDocumentEdited:isUnsavedChanges]; + [pool drain]; return GHOST_Window::setModifiedState(isUnsavedChanges); } @@ -631,12 +571,11 @@ GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextTyp case GHOST_kDrawingContextTypeOpenGL: if (!getValid()) break; - if(!m_fullScreen) - { pixelFormat = [m_openGLView pixelFormat]; tmpOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:m_openGLContext]; if (tmpOpenGLContext == nil) + success = GHOST_kFailure; break; #ifdef WAIT_FOR_VSYNC /* wait for vsync, to avoid tearing artifacts */ @@ -645,37 +584,8 @@ GHOST_TSuccess GHOST_WindowCocoa::installDrawingContext(GHOST_TDrawingContextTyp [m_openGLView setOpenGLContext:tmpOpenGLContext]; [tmpOpenGLContext setView:m_openGLView]; - //[m_openGLContext release]; + [m_openGLContext release]; m_openGLContext = tmpOpenGLContext; - } - /* - AGLPixelFormat pixelFormat; - if (!m_fullScreen) { - pixelFormat = ::aglChoosePixelFormat(0, 0, sPreferredFormatWindow); - m_aglCtx = ::aglCreateContext(pixelFormat, s_firstaglCtx); - if (!m_aglCtx) break; - if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; - success = ::aglSetDrawable(m_aglCtx, m_grafPtr) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; - } - else { - //GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL\n"); -GDHandle device=::GetMainDevice();pixelFormat=::aglChoosePixelFormat(&device,1,sPreferredFormatFullScreen); - m_aglCtx = ::aglCreateContext(pixelFormat, 0); - if (!m_aglCtx) break; - if (!s_firstaglCtx) s_firstaglCtx = m_aglCtx; - //GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): created OpenGL context\n"); - //::CGGetActiveDisplayList(0, NULL, &m_numDisplays) - success = ::aglSetFullScreen(m_aglCtx, m_fullScreenWidth, m_fullScreenHeight, 75, 0) == GL_TRUE ? GHOST_kSuccess : GHOST_kFailure; - - if (success == GHOST_kSuccess) { - GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL succeeded\n"); - } - else { - GHOST_PRINT("GHOST_WindowCocoa::installDrawingContext(): init full-screen OpenGL failed\n"); - } - - } - ::aglDestroyPixelFormat(pixelFormat);*/ break; case GHOST_kDrawingContextTypeNone: @@ -696,14 +606,16 @@ GHOST_TSuccess GHOST_WindowCocoa::removeDrawingContext() switch (m_drawingContextType) { case GHOST_kDrawingContextTypeOpenGL: [m_openGLView clearGLContext]; + [pool drain]; return GHOST_kSuccess; case GHOST_kDrawingContextTypeNone: + [pool drain]; return GHOST_kSuccess; break; default: + [pool drain]; return GHOST_kFailure; } - [pool drain]; } @@ -711,20 +623,7 @@ GHOST_TSuccess GHOST_WindowCocoa::invalidate() { GHOST_ASSERT(getValid(), "GHOST_WindowCocoa::invalidate(): window invalid") NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - if (!m_fullScreen) { - [m_openGLView setNeedsDisplay:YES]; - } - else { - //EventRef event; - //OSStatus status = ::CreateEvent(NULL, kEventClassWindow, kEventWindowUpdate, 0, 0, &event); - //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): created event " << status << " \n"); - //status = ::SetEventParameter(event, kEventParamDirectObject, typeWindowRef, sizeof(WindowRef), this); - //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): set event parameter " << status << " \n"); - //status = ::PostEventToQueue(::GetMainEventQueue(), event, kEventPriorityStandard); - //status = ::SendEventToEventTarget(event, ::GetApplicationEventTarget()); - //GHOST_PRINT("GHOST_WindowCocoa::invalidate(): added event to queue " << status << " \n"); - m_fullScreenDirty = true; - } + [m_openGLView setNeedsDisplay:YES]; [pool drain]; return GHOST_kSuccess; } @@ -803,11 +702,6 @@ void GHOST_WindowCocoa::loadCursor(bool visible, GHOST_TStandardCursor cursor) c } -bool GHOST_WindowCocoa::getFullScreenDirty() -{ - return m_fullScreen && m_fullScreenDirty; -} - GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) { From 3b8925c65505c1125a07da60a901ffb2fb21e9b0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 13:25:54 +0000 Subject: [PATCH 057/138] Particle Edit Mode: * Fix crash trying to enter particle mode when the particle modifier is disabled in the stack. * Fix redraw being very slow due to the draw function causing the object to be recalculated on each redraw (through PE_draw_object). * Removed the system where PE_get_current would automatically create the particle edit, this would run from poll() functions, which gave all kinds of issues, now it only creates the data on enter/exit and switching active particle system. --- source/blender/blenloader/intern/readfile.c | 2 +- source/blender/editors/include/ED_particle.h | 2 + .../blender/editors/physics/particle_edit.c | 39 +++++++++++++------ source/blender/makesrna/intern/rna_object.c | 13 ++++++- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 9b4ed4d11a7..184b584d188 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -3918,7 +3918,7 @@ static void direct_link_object(FileData *fd, Object *ob) ob->flag &= ~OB_FROMGROUP; /* editmode doesn't get saved in files, so should get cleared when reloading... */ - ob->mode &= ~OB_MODE_EDIT; + ob->mode &= ~(OB_MODE_EDIT|OB_MODE_PARTICLE_EDIT); ob->disp.first=ob->disp.last= NULL; diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index 3d7fc5ea15b..fcdaf8cb59d 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -46,6 +46,8 @@ int PE_start_edit(struct PTCacheEdit *edit); /* access */ struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob); +struct PTCacheEdit *PE_create_current(struct Scene *scene, struct Object *ob); +void PE_current_changed(struct Scene *scene, struct Object *ob); int PE_minmax(struct Scene *scene, float *min, float *max); struct ParticleEditSettings *PE_settings(struct Scene *scene); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index ac47ddebc1f..e3f54158fbb 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -194,7 +194,7 @@ ParticleEditSettings *PE_settings(Scene *scene) } /* always gets atleast the first particlesystem even if PSYS_CURRENT flag is not set */ -PTCacheEdit *PE_get_current(Scene *scene, Object *ob) +static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create) { ParticleEditSettings *pset= PE_settings(scene); PTCacheEdit *edit = NULL; @@ -232,18 +232,18 @@ PTCacheEdit *PE_get_current(Scene *scene, Object *ob) if(psys->flag & PSYS_CURRENT) { if(psys->part && psys->part->type == PART_HAIR) { if(psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) { - if(!psys->pointcache->edit) + if(create && !psys->pointcache->edit) PE_create_particle_edit(scene, ob, pid->cache, NULL); edit = pid->cache->edit; } else { - if(!psys->edit && psys->flag & PSYS_HAIR_DONE) + if(create && !psys->edit && psys->flag & PSYS_HAIR_DONE) PE_create_particle_edit(scene, ob, NULL, psys); edit = psys->edit; } } else { - if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) + if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) PE_create_particle_edit(scene, ob, pid->cache, psys); edit = pid->cache->edit; } @@ -252,13 +252,13 @@ PTCacheEdit *PE_get_current(Scene *scene, Object *ob) } } else if(pset->edittype == PE_TYPE_SOFTBODY && pid->type == PTCACHE_TYPE_SOFTBODY) { - if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) + if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) PE_create_particle_edit(scene, ob, pid->cache, NULL); edit = pid->cache->edit; break; } else if(pset->edittype == PE_TYPE_CLOTH && pid->type == PTCACHE_TYPE_CLOTH) { - if(pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) + if(create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) PE_create_particle_edit(scene, ob, pid->cache, NULL); edit = pid->cache->edit; break; @@ -273,6 +273,22 @@ PTCacheEdit *PE_get_current(Scene *scene, Object *ob) return edit; } +PTCacheEdit *PE_get_current(Scene *scene, Object *ob) +{ + return pe_get_current(scene, ob, 0); +} + +PTCacheEdit *PE_create_current(Scene *scene, Object *ob) +{ + return pe_get_current(scene, ob, 1); +} + +void PE_current_changed(Scene *scene, Object *ob) +{ + if(ob->mode == OB_MODE_PARTICLE_EDIT) + PE_create_current(scene, ob); +} + void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra) { ParticleEditSettings *pset=PE_settings(scene); @@ -1195,8 +1211,6 @@ void PE_update_object(Scene *scene, Object *ob, int useflag) if(edit->psys) edit->psys->flag &= ~PSYS_HAIR_UPDATED; - - DAG_id_flush_update(&ob->id, OB_RECALC_DATA); } /************************************************/ @@ -2409,7 +2423,6 @@ static int delete_exec(bContext *C, wmOperator *op) } PE_update_object(data.scene, data.ob, 0); - DAG_id_flush_update(&data.ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE_DATA, data.ob); @@ -3734,13 +3747,15 @@ int PE_minmax(Scene *scene, float *min, float *max) /* initialize needed data for bake edit */ static void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys) { - PTCacheEdit *edit= psys ? psys->edit : cache->edit; + PTCacheEdit *edit= (psys)? psys->edit : cache->edit; + ParticleSystemModifierData *psmd= (psys)? psys_get_modifier(ob, psys): NULL; POINT_P; KEY_K; ParticleData *pa = NULL; HairKey *hkey; int totpoint; - if(!psys && !cache) + /* no psmd->dm happens in case particle system modifier is not enabled */ + if(!(psys && psmd && psmd->dm) && !cache) return; if(cache && cache->flag & PTCACHE_DISK_CACHE) @@ -3850,10 +3865,12 @@ static int particle_edit_toggle_poll(bContext *C) static int particle_edit_toggle_exec(bContext *C, wmOperator *op) { + Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_active_object(C); if(!(ob->mode & OB_MODE_PARTICLE_EDIT)) { ob->mode |= OB_MODE_PARTICLE_EDIT; + PE_create_current(scene, ob); toggle_particle_cursor(C, 1); WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_MODE_PARTICLE, NULL); } diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 694eb7e23e4..611585c8809 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -102,6 +102,7 @@ EnumPropertyItem object_type_items[] = { #include "BLI_editVert.h" /* for EditMesh->mat_nr */ #include "ED_object.h" +#include "ED_particle.h" void rna_Object_update(bContext *C, PointerRNA *ptr) { @@ -460,12 +461,20 @@ static int rna_Object_active_particle_system_index_get(PointerRNA *ptr) return psys_get_current_num(ob); } -static void rna_Object_active_particle_system_index_set(struct PointerRNA *ptr, int value) +static void rna_Object_active_particle_system_index_set(PointerRNA *ptr, int value) { Object *ob= (Object*)ptr->id.data; psys_set_current_num(ob, value); } +static void rna_Object_particle_update(bContext *C, PointerRNA *ptr) +{ + Scene *scene= CTX_data_scene(C); + Object *ob= (Object*)ptr->id.data; + + PE_current_changed(scene, ob); +} + /* rotation - axis-angle */ static void rna_Object_rotation_axis_angle_get(PointerRNA *ptr, float *value) { @@ -1418,7 +1427,7 @@ static void rna_def_object(BlenderRNA *brna) prop= RNA_def_property(srna, "active_particle_system_index", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_funcs(prop, "rna_Object_active_particle_system_index_get", "rna_Object_active_particle_system_index_set", "rna_Object_active_particle_system_index_range"); RNA_def_property_ui_text(prop, "Active Particle System Index", "Index of active particle system slot."); - RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, NULL); + RNA_def_property_update(prop, NC_OBJECT|ND_DRAW, "rna_Object_particle_update"); /* restrict */ prop= RNA_def_property(srna, "restrict_view", PROP_BOOLEAN, PROP_NONE); From 105a53a29d3da99625b894ba13769fefb53e0974 Mon Sep 17 00:00:00 2001 From: Daniel Genrich Date: Fri, 9 Oct 2009 13:34:24 +0000 Subject: [PATCH 058/138] Bugfix for crash when clicking on "View->Properties". Was accessing unused memory here (uiBlock *block is uninitialized). If there is the need of uiBlockEndAlign() please get the valid uiBlock pointer from somewhere! --- source/blender/editors/space_view3d/view3d_buttons.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index b5a0ca079bc..0cdf849d453 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1130,7 +1130,7 @@ static void view3d_panel_object(const bContext *C, Panel *pa) tfp= v3d->properties_storage; // XXX uiSetButLock(object_is_libdata(ob), ERROR_LIBDATA_MESSAGE); - + /* if(ob->mode & (OB_MODE_VERTEX_PAINT|OB_MODE_WEIGHT_PAINT|OB_MODE_TEXTURE_PAINT)) { } else { @@ -1138,6 +1138,7 @@ static void view3d_panel_object(const bContext *C, Panel *pa) uiBlockEndAlign(block); } } + */ lim= 10000.0f*MAX2(1.0, v3d->grid); From cbd511743286b9af79e3deb86b9157fea3ec8eac Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Fri, 9 Oct 2009 13:56:35 +0000 Subject: [PATCH 059/138] * Show Smoke Field Weights only for Domains. --- release/scripts/ui/buttons_physics_smoke.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/scripts/ui/buttons_physics_smoke.py b/release/scripts/ui/buttons_physics_smoke.py index 53a7ec9c10c..b1523148a30 100644 --- a/release/scripts/ui/buttons_physics_smoke.py +++ b/release/scripts/ui/buttons_physics_smoke.py @@ -178,7 +178,8 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel): __default_closed__ = True def poll(self, context): - return (context.smoke) + smoke = context.smoke + return (smoke and smoke.smoke_type == 'TYPE_DOMAIN') def draw(self, context): domain = context.smoke.domain_settings From 8c96e2f4d284f76b6e0bdfbbd5fa9d1bc34b28ee Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 9 Oct 2009 14:35:54 +0000 Subject: [PATCH 060/138] - added ramp diffuse & spec factor rna props - made 3dspace camera editable - convert in object menu --- release/scripts/ui/buttons_material.py | 4 ++++ release/scripts/ui/space_view3d.py | 2 ++ source/blender/makesrna/intern/rna_material.c | 11 +++++++++++ source/blender/makesrna/intern/rna_space.c | 1 + 4 files changed, 18 insertions(+) diff --git a/release/scripts/ui/buttons_material.py b/release/scripts/ui/buttons_material.py index 03e11e003e2..fbd2df381e0 100644 --- a/release/scripts/ui/buttons_material.py +++ b/release/scripts/ui/buttons_material.py @@ -306,6 +306,8 @@ class MATERIAL_PT_diffuse(MaterialButtonsPanel): split = row.split(percentage=0.3) split.itemL(text="Blend:") split.itemR(mat, "diffuse_ramp_blend", text="") + row = layout.row() + row.itemR(mat, "diffuse_ramp_factor", text="Factor") class MATERIAL_PT_specular(MaterialButtonsPanel): __label__ = "Specular" @@ -358,6 +360,8 @@ class MATERIAL_PT_specular(MaterialButtonsPanel): split = row.split(percentage=0.3) split.itemL(text="Blend:") split.itemR(mat, "specular_ramp_blend", text="") + row = layout.row() + row.itemR(mat, "specular_ramp_factor", text="Factor") class MATERIAL_PT_sss(MaterialButtonsPanel): __label__ = "Subsurface Scattering" diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py index ecc4d298b94..33ae3472053 100644 --- a/release/scripts/ui/space_view3d.py +++ b/release/scripts/ui/space_view3d.py @@ -422,6 +422,8 @@ class VIEW3D_MT_object(bpy.types.Menu): layout.itemM("VIEW3D_MT_object_showhide") + layout.item_menu_enumO("object.convert", "target") + class VIEW3D_MT_object_clear(bpy.types.Menu): __label__ = "Clear" diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index b22b5916362..3366bc04c70 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -763,6 +763,17 @@ static void rna_def_material_colors(StructRNA *srna) RNA_def_property_ui_text(prop, "Specular Ramp Input", ""); RNA_def_property_update(prop, 0, "rna_Material_update"); + prop= RNA_def_property(srna, "diffuse_ramp_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "rampfac_col"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Diffuse Ramp Factor", "Blending factor (also uses alpha in Colorband)."); + RNA_def_property_update(prop, 0, "rna_Material_update"); + + prop= RNA_def_property(srna, "specular_ramp_factor", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "rampfac_spec"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Specular Ramp Factor", "Blending factor (also uses alpha in Colorband)."); + RNA_def_property_update(prop, 0, "rna_Material_update"); } static void rna_def_material_diffuse(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 422283c940f..f2ab9360856 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -593,6 +593,7 @@ static void rna_def_space_3dview(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data"); prop= RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_pointer_sdna(prop, NULL, "camera"); RNA_def_property_ui_text(prop, "Camera", "Active camera used in this view (when unlocked from the scene's active camera)."); RNA_def_property_update(prop, NC_SPACE|ND_SPACE_VIEW3D, NULL); From 8f57b368ca89b8fdd6e2c3bd4f0adf145ab820a1 Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Fri, 9 Oct 2009 14:42:36 +0000 Subject: [PATCH 061/138] Cocoa : Implement OS X support for Campbell's new continuous grab feature --- intern/ghost/intern/GHOST_SystemCocoa.mm | 27 ++++++++++--- intern/ghost/intern/GHOST_WindowCocoa.h | 7 ++++ intern/ghost/intern/GHOST_WindowCocoa.mm | 50 ++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 481dd705265..2dfdcf7bcec 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -798,7 +798,7 @@ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt3 { NSPoint mouseLoc = [NSEvent mouseLocation]; - // Convert the coordinates to screen coordinates + // Returns the mouse location in screen coordinates x = (GHOST_TInt32)mouseLoc.x; y = (GHOST_TInt32)mouseLoc.y; return GHOST_kSuccess; @@ -808,7 +808,10 @@ GHOST_TSuccess GHOST_SystemCocoa::getCursorPosition(GHOST_TInt32& x, GHOST_TInt3 GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 y) const { float xf=(float)x, yf=(float)y; - + + //Quartz Display Services uses the old coordinates (top left origin) + yf = [[NSScreen mainScreen] frame].size.height -yf; + CGAssociateMouseAndMouseCursorPosition(false); CGWarpMouseCursorPosition(CGPointMake(xf, yf)); CGAssociateMouseAndMouseCursorPosition(true); @@ -1080,7 +1083,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleTabletEvent(void *eventPtr, short eventT GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) { NSEvent *event = (NSEvent *)eventPtr; - GHOST_IWindow* window = m_windowManager->getActiveWindow(); + GHOST_Window* window = (GHOST_Window*)m_windowManager->getActiveWindow(); if (!window) { return GHOST_kFailure; @@ -1141,8 +1144,22 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) } case NSMouseMoved: { - NSPoint mousePos = [event locationInWindow]; - pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); + if(window->getCursorWarp()) { + GHOST_TInt32 x_warp, y_warp, x_accum, y_accum; + + window->getCursorWarpPos(x_warp, y_warp); + + window->getCursorWarpAccum(x_accum, y_accum); + x_accum += [event deltaX]; + y_accum += [event deltaY]; + window->setCursorWarpAccum(x_accum, y_accum); + + pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum)); + } + else { //Normal cursor operation: send mouse position in window + NSPoint mousePos = [event locationInWindow]; + pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); + } break; } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 8c2919d1ce2..7a39d9ab54a 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -236,6 +236,13 @@ protected: */ virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + /** + * Sets the cursor grab on the window using + * native window system calls. + * @param warp Only used when grab is enabled, hides the mouse and allows gragging outside the screen. + */ + virtual GHOST_TSuccess setWindowCursorGrab(bool grab, bool warp, bool restore); + /** * Sets the cursor shape on the window using * native window system calls. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index f4c9172c668..1d604553cc1 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -711,6 +711,56 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) return GHOST_kSuccess; } + +GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool restore) +{ + if (grab) + { + if(warp) { + m_systemCocoa->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + + setCursorWarpAccum(0, 0); + setWindowCursorVisibility(false); + m_cursorWarp= true; + } + return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; + } + else { + if(m_cursorWarp) + {/* are we exiting warp */ + setWindowCursorVisibility(true); + /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ + if(restore) { + GHOST_Rect bounds; + GHOST_TInt32 x_new, y_new, x_rel, y_rel; + + getClientBounds(bounds); + printf("\ncursor ungrab with restore"); + x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0]; + y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1]; + + screenToClient(x_new, y_new, x_rel, y_rel); + + if(x_rel < 0) x_new = (x_new-x_rel) + 2; + if(y_rel < 0) y_new = (y_new-y_rel) + 2; + if(x_rel > bounds.getWidth()) x_new -= (x_rel-bounds.getWidth()) + 2; + if(y_rel > bounds.getHeight()) y_new -= (y_rel-bounds.getHeight()) + 2; + + clientToScreen(x_new, y_new, x_rel, y_rel); + m_systemCocoa->setCursorPosition(x_rel, y_rel); + + } + else { + m_systemCocoa->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + } + + setCursorWarpAccum(0, 0); + m_cursorWarp= false; + } + return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; + } + +} GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) { From dfbe2f9974f8e6d45d821fc6a16e7d3d32cd5faa Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 15:09:21 +0000 Subject: [PATCH 062/138] Fix for crash when saving a render result image, then rendering again. The saved image would still point to the render buffer, which was freed again on render. This is not a real solution but avoids the crash for now. --- source/blender/editors/space_image/image_ops.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 91316fba4d0..d5bd736f307 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -813,12 +813,25 @@ static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOpera ibuf->userflags &= ~IB_BITMAPDIRTY; /* change type? */ + if(ima->type==IMA_TYPE_R_RESULT) { + ima->type= IMA_TYPE_IMAGE; + + /* workaround to ensure the render result buffer is no longer used + * by this image, otherwise can crash when a new render result is + * created. */ + if(ibuf->rect && !(ibuf->mall & IB_rect)) + imb_freerectImBuf(ibuf); + if(ibuf->rect_float && !(ibuf->mall & IB_rectfloat)) + imb_freerectfloatImBuf(ibuf); + if(ibuf->zbuf && !(ibuf->mall & IB_zbuf)) + IMB_freezbufImBuf(ibuf); + if(ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat)) + IMB_freezbuffloatImBuf(ibuf); + } if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) { ima->source= IMA_SRC_FILE; ima->type= IMA_TYPE_IMAGE; } - if(ima->type==IMA_TYPE_R_RESULT) - ima->type= IMA_TYPE_IMAGE; /* name image as how we saved it */ len= strlen(name); From 9bf20b5ec0dd4886cd66c51ea4984861bf49611a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 15:25:19 +0000 Subject: [PATCH 063/138] UI scripts: * Fix AAO showing Distance property even though it is not supported. * Fix texture buttons not displaying texture stack from the node material. * Small visual tweak to particle mode options. --- release/scripts/ui/buttons_texture.py | 18 ++++++++++++++---- release/scripts/ui/buttons_world.py | 3 ++- release/scripts/ui/space_view3d_toolbar.py | 4 +--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/release/scripts/ui/buttons_texture.py b/release/scripts/ui/buttons_texture.py index b76f35c3ec3..62281695177 100644 --- a/release/scripts/ui/buttons_texture.py +++ b/release/scripts/ui/buttons_texture.py @@ -1,6 +1,16 @@ import bpy +def active_node_mat(mat): + if mat: + mat_node = mat.active_node_material + if mat_node: + return mat_node + else: + return mat + + return None + class TextureButtonsPanel(bpy.types.Panel): __space_type__ = 'PROPERTIES' __region_type__ = 'WINDOW' @@ -18,7 +28,7 @@ class TEXTURE_PT_preview(TextureButtonsPanel): tex = context.texture slot = context.texture_slot - ma = context.material + ma = active_node_mat(context.material) la = context.lamp wo = context.world br = context.brush @@ -45,7 +55,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel): tex = context.texture - id = context.material + id = active_node_mat(context.material) if not id: id = context.lamp if not id: id = context.world if not id: id = context.brush @@ -129,7 +139,7 @@ class TEXTURE_PT_mapping(TextureSlotPanel): def draw(self, context): layout = self.layout - ma = context.material + ma = active_node_mat(context.material) la = context.lamp wo = context.world br = context.brush @@ -202,7 +212,7 @@ class TEXTURE_PT_influence(TextureSlotPanel): def draw(self, context): layout = self.layout - ma = context.material + ma = active_node_mat(context.material) la = context.lamp wo = context.world br = context.brush diff --git a/release/scripts/ui/buttons_world.py b/release/scripts/ui/buttons_world.py index 3134c0ce46b..b64efc1048d 100644 --- a/release/scripts/ui/buttons_world.py +++ b/release/scripts/ui/buttons_world.py @@ -129,7 +129,8 @@ class WORLD_PT_ambient_occlusion(WorldButtonsPanel): col = split.column() col.itemL(text="Attenuation:") - col.itemR(ao, "distance") + if ao.gather_method == 'RAYTRACE': + col.itemR(ao, "distance") col.itemR(ao, "falloff") sub = col.row() sub.active = ao.falloff diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py index 4c1b54ea8e6..ab1e161b928 100644 --- a/release/scripts/ui/space_view3d_toolbar.py +++ b/release/scripts/ui/space_view3d_toolbar.py @@ -676,9 +676,7 @@ class VIEW3D_PT_tools_particlemode(View3DPanel): pe = context.tool_settings.particle_edit ob = pe.object - row = layout.row() - row.itemL(text="Edit:") - row.itemR(pe, "type", text="") + layout.itemR(pe, "type", text="") if pe.type == 'PARTICLES': if ob.particle_systems: From 638ed7d0a840fdde028cff27dd5a54290a7ab60f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 15:47:35 +0000 Subject: [PATCH 064/138] Fix background image sometimes drawing into depth buffer, causing wireframes to be occluded. --- source/blender/editors/space_view3d/view3d_draw.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 06d0832cb8b..fac3f9fb555 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1413,6 +1413,7 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d) } if(v3d->zbuf) glDisable(GL_DEPTH_TEST); + glDepthMask(0); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -1433,6 +1434,8 @@ static void draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d) wmPopMatrix(); glDisable(GL_BLEND); + + glDepthMask(1); if(v3d->zbuf) glEnable(GL_DEPTH_TEST); } From 1234f4709b3e65e44016a8d3419f64d9cf25aae8 Mon Sep 17 00:00:00 2001 From: Damien Plisson Date: Fri, 9 Oct 2009 17:42:31 +0000 Subject: [PATCH 065/138] Cocoa : Bug fix for continuous grab feature implementation --- intern/ghost/intern/GHOST_SystemCocoa.mm | 7 +-- intern/ghost/intern/GHOST_WindowCocoa.h | 5 +++ intern/ghost/intern/GHOST_WindowCocoa.mm | 54 ++++++++++++++++-------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 2dfdcf7bcec..8bbe446616d 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -812,9 +812,9 @@ GHOST_TSuccess GHOST_SystemCocoa::setCursorPosition(GHOST_TInt32 x, GHOST_TInt32 //Quartz Display Services uses the old coordinates (top left origin) yf = [[NSScreen mainScreen] frame].size.height -yf; - CGAssociateMouseAndMouseCursorPosition(false); + //CGAssociateMouseAndMouseCursorPosition(false); CGWarpMouseCursorPosition(CGPointMake(xf, yf)); - CGAssociateMouseAndMouseCursorPosition(true); + //CGAssociateMouseAndMouseCursorPosition(true); return GHOST_kSuccess; } @@ -1151,7 +1151,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) window->getCursorWarpAccum(x_accum, y_accum); x_accum += [event deltaX]; - y_accum += [event deltaY]; + y_accum += -[event deltaY]; //Strange Apple implementation (inverted coordinates for the deltaY) ... window->setCursorWarpAccum(x_accum, y_accum); pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, x_warp+x_accum, y_warp+y_accum)); @@ -1159,6 +1159,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) else { //Normal cursor operation: send mouse position in window NSPoint mousePos = [event locationInWindow]; pushEvent(new GHOST_EventCursor([event timestamp], GHOST_kEventCursorMove, window, mousePos.x, mousePos.y)); + window->setCursorWarpAccum(0, 0); //Mouse motion occured between two cursor warps, so we can reset the delta counter } break; } diff --git a/intern/ghost/intern/GHOST_WindowCocoa.h b/intern/ghost/intern/GHOST_WindowCocoa.h index 7a39d9ab54a..bc0dd9db13d 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.h +++ b/intern/ghost/intern/GHOST_WindowCocoa.h @@ -236,6 +236,11 @@ protected: */ virtual GHOST_TSuccess setWindowCursorVisibility(bool visible); + /** + * Sets the cursor warp accumulator. Overriden for workaround due to Cocoa next event after cursor set giving delta values non zero + */ + inline virtual bool setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y); + /** * Sets the cursor grab on the window using * native window system calls. diff --git a/intern/ghost/intern/GHOST_WindowCocoa.mm b/intern/ghost/intern/GHOST_WindowCocoa.mm index 1d604553cc1..205c18e29ba 100644 --- a/intern/ghost/intern/GHOST_WindowCocoa.mm +++ b/intern/ghost/intern/GHOST_WindowCocoa.mm @@ -712,18 +712,33 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorVisibility(bool visible) return GHOST_kSuccess; } + +//Override this method to provide set feature even if not in warp +inline bool GHOST_WindowCocoa::setCursorWarpAccum(GHOST_TInt32 x, GHOST_TInt32 y) +{ + m_cursorWarpAccumPos[0]= x; + m_cursorWarpAccumPos[1]= y; + + return GHOST_kSuccess; +} + + GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool restore) { + printf("\ncursor grab %i",grab); if (grab) { + //No need to perform grab without warp as it is always on in OS X if(warp) { - m_systemCocoa->getCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); - - setCursorWarpAccum(0, 0); - setWindowCursorVisibility(false); + GHOST_TInt32 x_old,y_old; + m_cursorWarp= true; + m_systemCocoa->getCursorPosition(x_old,y_old); + screenToClient(x_old, y_old, m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + //Warp position is stored in client (window base) coordinates + setWindowCursorVisibility(false); + return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } - return CGAssociateMouseAndMouseCursorPosition(false) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } else { if(m_cursorWarp) @@ -732,34 +747,37 @@ GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorGrab(bool grab, bool warp, bool /* Almost works without but important otherwise the mouse GHOST location can be incorrect on exit */ if(restore) { GHOST_Rect bounds; - GHOST_TInt32 x_new, y_new, x_rel, y_rel; + GHOST_TInt32 x_new, y_new, x_cur, y_cur; getClientBounds(bounds); - printf("\ncursor ungrab with restore"); x_new= m_cursorWarpInitPos[0]+m_cursorWarpAccumPos[0]; y_new= m_cursorWarpInitPos[1]+m_cursorWarpAccumPos[1]; - screenToClient(x_new, y_new, x_rel, y_rel); + if(x_new < 0) x_new = 0; + if(y_new < 0) y_new = 0; + if(x_new > bounds.getWidth()) x_new = bounds.getWidth(); + if(y_new > bounds.getHeight()) y_new = bounds.getHeight(); - if(x_rel < 0) x_new = (x_new-x_rel) + 2; - if(y_rel < 0) y_new = (y_new-y_rel) + 2; - if(x_rel > bounds.getWidth()) x_new -= (x_rel-bounds.getWidth()) + 2; - if(y_rel > bounds.getHeight()) y_new -= (y_rel-bounds.getHeight()) + 2; - - clientToScreen(x_new, y_new, x_rel, y_rel); - m_systemCocoa->setCursorPosition(x_rel, y_rel); + //get/set cursor position works in screen coordinates + clientToScreen(x_new, y_new, x_cur, y_cur); + m_systemCocoa->setCursorPosition(x_cur, y_cur); + //As Cocoa will give as first deltaX,deltaY this change in cursor position, we need to compensate for it + //Issue appearing in case of two transform operations conducted w/o mouse motion in between + x_new=m_cursorWarpAccumPos[0]; + y_new=m_cursorWarpAccumPos[1]; + setCursorWarpAccum(-x_new, -y_new); } else { m_systemCocoa->setCursorPosition(m_cursorWarpInitPos[0], m_cursorWarpInitPos[1]); + setCursorWarpAccum(0, 0); } - setCursorWarpAccum(0, 0); m_cursorWarp= false; + return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } - return CGAssociateMouseAndMouseCursorPosition(true) == kCGErrorSuccess ? GHOST_kSuccess : GHOST_kFailure; } - + return GHOST_kSuccess; } GHOST_TSuccess GHOST_WindowCocoa::setWindowCursorShape(GHOST_TStandardCursor shape) From 7d07342c09f82cea15ad4767eed407483c5661a9 Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Fri, 9 Oct 2009 20:44:50 +0000 Subject: [PATCH 066/138] -f argument uses MINFRAME instead of 1 (makes it possible to render negative frames on command line). Not that useful, but it's good to use the same limit everywhere. --- source/creator/creator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/creator/creator.c b/source/creator/creator.c index 6f64628b467..6f90c2ffe84 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -619,7 +619,7 @@ int main(int argc, char **argv) int frame = atoi(argv[a]); Render *re = RE_NewRender(scene->id.name); - frame = MIN2(MAXFRAME, MAX2(1, frame)); + frame = MIN2(MAXFRAME, MAX2(MINAFRAME, frame)); RE_BlenderAnim(re, scene, frame, frame, scene->frame_step); } From a5b30906ad7ae583631fb0f20ca5cf1cbebebd2f Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 20:59:44 +0000 Subject: [PATCH 067/138] Bugfix: texture nodes render without OSA was using uninitialized variables, giving incorrect results. --- source/blender/render/intern/source/texture.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/texture.c index aee2d8d1866..64683e8e7da 100644 --- a/source/blender/render/intern/source/texture.c +++ b/source/blender/render/intern/source/texture.c @@ -1182,7 +1182,8 @@ static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, texres->talpha= 0; /* is set when image texture returns alpha (considered premul) */ if(tex->use_nodes && tex->nodetree) { - retval = evalnodes(tex, texvec, dxt, dyt, texres, thread, which_output); + if(osatex) retval = evalnodes(tex, texvec, dxt, dyt, texres, thread, which_output); + else retval = evalnodes(tex, texvec, NULL, NULL, texres, thread, which_output); } else switch(tex->type) { From e5d61c7f41e59bf8b8edf19bd9e57d87741f9cee Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 21:45:14 +0000 Subject: [PATCH 068/138] Bugfix: separate mesh did not preserve UV/Color layers. --- source/blender/editors/mesh/editmesh.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c index 1e3105f5c97..52744c81b7e 100644 --- a/source/blender/editors/mesh/editmesh.c +++ b/source/blender/editors/mesh/editmesh.c @@ -1342,11 +1342,14 @@ static int mesh_separate_selected(Scene *scene, Base *editbase) ED_base_object_select(basenew, BA_DESELECT); /* 2 */ - basenew->object->data= menew= add_mesh(me->id.name); /* empty */ + basenew->object->data= menew= add_mesh(me->id.name+2); /* empty */ assign_matarar(basenew->object, give_matarar(obedit), *give_totcolp(obedit)); /* new in 2.5 */ me->id.us--; make_editMesh(scene, basenew->object); emnew= menew->edit_mesh; + CustomData_copy(&em->vdata, &emnew->vdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); + CustomData_copy(&em->edata, &emnew->edata, CD_MASK_EDITMESH, CD_DEFAULT, 0); + CustomData_copy(&em->fdata, &emnew->fdata, CD_MASK_EDITMESH, CD_DEFAULT, 0); /* 3 */ /* SPLIT: first make duplicate */ @@ -1389,6 +1392,8 @@ static int mesh_separate_selected(Scene *scene, Base *editbase) /* 5 */ load_editMesh(scene, basenew->object); free_editMesh(emnew); + MEM_freeN(menew->edit_mesh); + menew->edit_mesh= NULL; /* hashedges are invalid now, make new! */ editMesh_set_hash(em); From ca77d6dabb0c9fba7f5862cc09294fc82bdd795a Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 21:50:33 +0000 Subject: [PATCH 069/138] Animation playback can now also be cancelled with ESC key. --- source/blender/editors/screen/screen_ops.c | 35 ++++++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 7ba83753fee..30fdb5b2c95 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2384,6 +2384,29 @@ static void SCREEN_OT_animation_play(wmOperatorType *ot) RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate and stay in sync with audio."); } +static int screen_animation_cancel(bContext *C, wmOperator *op, wmEvent *event) +{ + bScreen *screen= CTX_wm_screen(C); + + if(screen->animtimer) + return screen_animation_play(C, op, event); + + return OPERATOR_PASS_THROUGH; +} + +static void SCREEN_OT_animation_cancel(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Cancel Animation"; + ot->description= "Cancel animation."; + ot->idname= "SCREEN_OT_animation_cancel"; + + /* api callbacks */ + ot->invoke= screen_animation_cancel; + + ot->poll= ED_operator_screenactive; +} + /* ************** border select operator (template) ***************************** */ /* operator state vars used: (added by default WM callbacks) @@ -2994,6 +3017,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *unused) /* test if we have a temp screen in front */ if(CTX_wm_window(C)->screen->full==SCREENTEMP) { wm_window_lower(CTX_wm_window(C)); + return OPERATOR_FINISHED; } /* determine if render already shows */ else if(sima->flag & SI_PREVSPACE) { @@ -3005,13 +3029,16 @@ static int render_view_cancel_exec(bContext *C, wmOperator *unused) } else ED_area_prevspace(C); + + return OPERATOR_FINISHED; } else if(sima->flag & SI_FULLWINDOW) { sima->flag &= ~SI_FULLWINDOW; ed_screen_fullarea(C, sa); - } - - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; + } + + return OPERATOR_PASS_THROUGH; } static void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot) @@ -3268,6 +3295,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(SCREEN_OT_animation_step); WM_operatortype_append(SCREEN_OT_animation_play); + WM_operatortype_append(SCREEN_OT_animation_cancel); /* render */ WM_operatortype_append(SCREEN_OT_render); @@ -3408,6 +3436,7 @@ void ED_keymap_screen(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", KKEY, KM_PRESS, 0, LKEY); RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1); + WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0); keymap_modal_set(keyconf); } From 578bb93ada1c9d6e6e158149ba2cb0926ce1ea6c Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 9 Oct 2009 22:00:33 +0000 Subject: [PATCH 070/138] Add reload button for image textures. --- .../editors/space_image/image_buttons.c | 6 +++-- .../blender/editors/space_image/image_ops.c | 22 ++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index e2990a6d919..87b6ec8bb71 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -943,6 +943,8 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn cb->prop= prop; cb->iuser= iuser; + uiLayoutSetContextPointer(layout, "edit_image", &imaptr); + if(!compact) uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL); @@ -992,9 +994,9 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn uiItemR(row, NULL, 0, &imaptr, "source", (compact)? 0: UI_ITEM_R_EXPAND); if(ima->source != IMA_SRC_GENERATED) { - row= uiLayoutRow(layout, 0); + row= uiLayoutRow(layout, 1); uiItemR(row, "", 0, &imaptr, "filename", 0); - //uiItemO(row, "Reload", 0, "image.reload"); + uiItemO(row, "", ICON_FILE_REFRESH, "image.reload"); } // XXX what was this for? diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index d5bd736f307..482750e5b2e 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -108,6 +108,11 @@ static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac) sima_zoom_set(sima, ar, sima->zoom*zoomfac); } +static int image_poll(bContext *C) +{ + return (CTX_data_edit_image(C) != NULL); +} + static int space_image_poll(bContext *C) { SpaceImage *sima= CTX_wm_space_image(C); @@ -1070,19 +1075,16 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot) static int reload_exec(bContext *C, wmOperator *op) { - SpaceImage *sima; + Image *ima= CTX_data_edit_image(C); + SpaceImage *sima= CTX_wm_space_image(C); - /* retrieve state */ - sima= CTX_wm_space_image(C); - - if(!sima->image) + if(!ima) return OPERATOR_CANCELLED; - BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD); - /* ED_space_image_set(C, sima, scene, obedit, NULL); - do we really need this? */ + // XXX other users? + BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD); - // XXX BIF_preview_changed(ID_TE); - WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image); + WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima); ED_area_tag_redraw(CTX_wm_area(C)); return OPERATOR_FINISHED; @@ -1096,7 +1098,7 @@ void IMAGE_OT_reload(wmOperatorType *ot) /* api callbacks */ ot->exec= reload_exec; - ot->poll= space_image_poll; + ot->poll= image_poll; /* flags */ ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; From 0b23e65e86466837f2a8329797e907da3cd98fdc Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Fri, 9 Oct 2009 22:06:23 +0000 Subject: [PATCH 071/138] * more small raytrace fixes --- source/blender/render/intern/source/volumetric.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c index fd7ffc8c845..7cb165ccaea 100644 --- a/source/blender/render/intern/source/volumetric.c +++ b/source/blender/render/intern/source/volumetric.c @@ -136,6 +136,7 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco, isect->lay= -1; if (intersect_type == VOL_BOUNDS_DEPTH) { + isect->skip = RE_SKIP_VLR_NEIGHBOUR; isect->orig.face = (void*)shi->vlr; isect->orig.ob = (void*)shi->obi; } else if (intersect_type == VOL_BOUNDS_SS) { From fb561fb4c8849523ce11483f8f8d6a2c4f8aef36 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 9 Oct 2009 22:09:48 +0000 Subject: [PATCH 072/138] added mesh to curve conversion (edge loops only) like the script in 2.4x --- source/blender/blenkernel/BKE_mesh.h | 1 + source/blender/blenkernel/intern/mesh.c | 175 ++++++++++++++++++ source/blender/editors/object/object_add.c | 15 +- source/blender/makesrna/intern/rna_fluidsim.c | 2 +- 4 files changed, 191 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 24e7b3957a7..d2f5e0faa0f 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -71,6 +71,7 @@ struct Mesh *get_mesh(struct Object *ob); void set_mesh(struct Object *ob, struct Mesh *me); void mball_to_mesh(struct ListBase *lb, struct Mesh *me); void nurbs_to_mesh(struct Object *ob); +void mesh_to_curve(struct Scene *scene, struct Object *ob); void free_dverts(struct MDeformVert *dvert, int totvert); void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */ void mesh_delete_material_index(struct Mesh *me, int index); diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 431543f8dbd..391aa0ec32f 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -42,6 +42,7 @@ #include "DNA_ID.h" #include "DNA_curve_types.h" +#include "DNA_scene_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_image_types.h" @@ -70,6 +71,7 @@ #include "BLI_blenlib.h" #include "BLI_editVert.h" #include "BLI_arithb.h" +#include "BLI_edgehash.h" EditMesh *BKE_mesh_get_editmesh(Mesh *me) @@ -952,6 +954,179 @@ void nurbs_to_mesh(Object *ob) } +typedef struct EdgeLink { + Link *next, *prev; + void *edge; +} EdgeLink; + +typedef struct VertLink { + Link *next, *prev; + int index; +} VertLink; + +static void prependPolyLineVert(ListBase *lb, int index) +{ + VertLink *vl= MEM_callocN(sizeof(VertLink), "VertLink"); + vl->index = index; + BLI_addhead(lb, vl); +} + +static void appendPolyLineVert(ListBase *lb, int index) +{ + VertLink *vl= MEM_callocN(sizeof(VertLink), "VertLink"); + vl->index = index; + BLI_addtail(lb, vl); +} + +void mesh_to_curve(Scene *scene, Object *ob) +{ + /* make new mesh data from the original copy */ + DerivedMesh *dm= mesh_get_derived_final(scene, ob, CD_MASK_MESH); + + MVert *mv, *mverts= dm->getVertArray(dm); + MEdge *med, *medge= dm->getEdgeArray(dm); + MFace *mf, *mface= dm->getFaceArray(dm); + + int totvert = dm->getNumVerts(dm); + int totedge = dm->getNumEdges(dm); + int totface = dm->getNumFaces(dm); + int totedges = 0; + int i; + + EdgeHash *eh = BLI_edgehash_new(); + EdgeHash *eh_edge = BLI_edgehash_new(); + + mf= mface; + for (i = 0; i < totface; i++, mf++) { + if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) + BLI_edgehash_insert(eh, mf->v1, mf->v2, NULL); + if (!BLI_edgehash_haskey(eh, mf->v2, mf->v3)) + BLI_edgehash_insert(eh, mf->v2, mf->v3, NULL); + + if (mf->v4) { + if (!BLI_edgehash_haskey(eh, mf->v3, mf->v4)) + BLI_edgehash_insert(eh, mf->v3, mf->v4, NULL); + if (!BLI_edgehash_haskey(eh, mf->v4, mf->v1)) + BLI_edgehash_insert(eh, mf->v4, mf->v1, NULL); + } else { + if (!BLI_edgehash_haskey(eh, mf->v3, mf->v1)) + BLI_edgehash_insert(eh, mf->v3, mf->v1, NULL); + } + } + + ListBase edges = {NULL, NULL}; + EdgeLink *edl; + + med= medge; + for(i=0; iv1, med->v2)) { + BLI_edgehash_insert(eh_edge, med->v1, med->v2, NULL); + + edl= MEM_callocN(sizeof(EdgeLink), "EdgeLink"); + edl->edge= med; + + BLI_addtail(&edges, edl); totedges++; + } + } + BLI_edgehash_free(eh_edge, NULL); + BLI_edgehash_free(eh, NULL); + + if(edges.first) { + Curve *cu = add_curve(ob->id.name+2, OB_CURVE); + cu->flag |= CU_3D; + + while(edges.first) { + ListBase polyline = {NULL, NULL}; + int closed = FALSE; + int totpoly= 0; + MEdge *med_current= ((EdgeLink *)edges.last)->edge; + int startVert= med_current->v1; + int endVert= med_current->v2; + + appendPolyLineVert(&polyline, startVert); totpoly++; + appendPolyLineVert(&polyline, endVert); totpoly++; + BLI_freelinkN(&edges, edges.last); totedges--; + + int ok= TRUE; + + while(ok) { + ok = FALSE; + i= totedges; + while(i) { + i-=1; + edl= BLI_findlink(&edges, i); + MEdge *ed= edl->edge; + + if(ed->v1==endVert) { + endVert = ed->v2; + appendPolyLineVert(&polyline, ed->v2); totpoly++; + BLI_freelinkN(&edges, edl); totedges--; + ok= TRUE; + } + else if(ed->v2==endVert) { + endVert = ed->v1; + appendPolyLineVert(&polyline, endVert); totpoly++; + BLI_freelinkN(&edges, edl); totedges--; + ok= TRUE; + } + else if(ed->v1==startVert) { + startVert = ed->v2; + prependPolyLineVert(&polyline, startVert); totpoly++; + BLI_freelinkN(&edges, edl); totedges--; + ok= TRUE; + } + else if(ed->v2==startVert) { + startVert = ed->v1; + prependPolyLineVert(&polyline, startVert); totpoly++; + BLI_freelinkN(&edges, edl); totedges--; + ok= TRUE; + } + } + } + + /* Now we have a polyline, make into a curve */ + if(startVert==endVert) { + BLI_freelinkN(&polyline, polyline.last); + totpoly--; + closed = TRUE; + } + + /* --- nurbs --- */ + Nurb *nu; + BPoint *bp; + + /* create new 'nurb' within the curve */ + nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb"); + + nu->pntsu= totpoly; + nu->pntsv= 1; + nu->orderu= 4; + nu->flagu= 2 | (closed ? CU_CYCLIC:0); /* endpoint */ + nu->resolu= 12; + + nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*totpoly, "bpoints"); + + /* add points */ + VertLink *vl= polyline.first; + for (i=0, bp=nu->bp; i < totpoly; i++, bp++, vl=vl->next) { + VecCopyf(bp->vec, mverts[vl->index].co); + bp->f1= SELECT; + bp->radius = bp->weight = 1.0; + } + BLI_freelistN(&polyline); + + /* add nurb to curve */ + BLI_addtail(&cu->nurb, nu); + /* --- done with nurbs --- */ + } + + ob->data= cu; + ob->type= OB_CURVE; + } + + dm->release(dm); +} + void mesh_delete_material_index(Mesh *me, int index) { int i; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index c552a2954b7..47053ea6d93 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1035,6 +1035,14 @@ static void curvetomesh(Scene *scene, Object *ob) object_free_modifiers(ob); } +static void meshtocurve(Scene *scene, Object *ob) +{ + mesh_to_curve(scene, ob); + + if(ob->type == OB_CURVE) + object_free_modifiers(ob); +} + static int convert_poll(bContext *C) { Object *obact= CTX_data_active_object(C); @@ -1071,6 +1079,11 @@ static int convert_exec(bContext *C, wmOperator *op) if(ob->flag & OB_DONE) continue; + else if (ob->type==OB_MESH && target == OB_CURVE) { + ob->flag |= OB_DONE; + meshtocurve(scene, ob); + ob->recalc |= OB_RECALC; + } else if(ob->type==OB_MESH && ob->modifiers.first) { /* converting a mesh with no modifiers causes a segfault */ ob->flag |= OB_DONE; basedel = base; @@ -1096,7 +1109,7 @@ static int convert_exec(bContext *C, wmOperator *op) /* make new mesh data from the original copy */ dm= mesh_get_derived_final(scene, ob1, CD_MASK_MESH); /* dm= mesh_create_derived_no_deform(ob1, NULL); this was called original (instead of get_derived). man o man why! (ton) */ - + DM_to_mesh(dm, ob1->data); dm->release(dm); diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 5b05948857e..ae52c811c92 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -114,7 +114,7 @@ static void rna_FluidSettings_update_type(bContext *C, PointerRNA *ptr) sprintf(psmd->modifier.name, "FluidParticleSystem" ); psmd->psys= psys; BLI_addtail(&ob->modifiers, psmd); - modifier_unique_name(&ob->modifiers, psmd); + modifier_unique_name(&ob->modifiers, (ModifierData *)psmd); } } else { From f9bb4e3195d6b1c6be31306d83fe15d7b034a2cb Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 9 Oct 2009 23:34:52 +0000 Subject: [PATCH 073/138] * Added Grease Pencil Operator buttons to the Toolshelf * Cancelling loopcuts with EscKey or RMB now works again. --- release/scripts/ui/space_view3d_toolbar.py | 48 ++++++++++++++++++++++ source/blender/editors/mesh/loopcut.c | 16 ++++++-- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py index ab1e161b928..d93a2d26040 100644 --- a/release/scripts/ui/space_view3d_toolbar.py +++ b/release/scripts/ui/space_view3d_toolbar.py @@ -38,6 +38,12 @@ class VIEW3D_PT_tools_objectmode(View3DPanel): col.itemO("anim.insert_keyframe_menu", text="Insert") col.itemO("anim.delete_keyframe_v3d", text="Remove") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -85,6 +91,12 @@ class VIEW3D_PT_tools_meshedit(View3DPanel): col.itemO("mesh.uvs_rotate") col.itemO("mesh.uvs_mirror") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -126,6 +138,12 @@ class VIEW3D_PT_tools_curveedit(View3DPanel): col.itemO("curve.extrude") col.itemO("curve.subdivide") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -159,6 +177,12 @@ class VIEW3D_PT_tools_surfaceedit(View3DPanel): col.itemO("curve.extrude") col.itemO("curve.subdivide") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -216,6 +240,12 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel): col.itemL(text="Modeling:") col.itemO("armature.extrude") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -237,6 +267,12 @@ class VIEW3D_PT_tools_mballedit(View3DPanel): col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -258,6 +294,12 @@ class VIEW3D_PT_tools_latticeedit(View3DPanel): col.itemO("tfm.rotate") col.itemO("tfm.resize", text="Scale") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") @@ -302,6 +344,12 @@ class VIEW3D_PT_tools_posemode(View3DPanel): col.itemO("pose.push", text="Push") col.itemO("pose.breakdown", text="Breakdowner") + col = layout.column(align=True) + col.itemL(text="Grease Pencil:") + col.item_enumO("gpencil.draw", "mode", 'DRAW', text="Draw Freehand") + col.item_enumO("gpencil.draw", "mode", 'DRAW_STRAIGHT', text="Straight Line") + col.item_enumO("gpencil.draw", "mode", 'ERASER', text="Eraser") + col = layout.column(align=True) col.itemL(text="Repeat:") col.itemO("screen.repeat_last") diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index e58025ac6ce..4ef25238a84 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -384,18 +384,28 @@ static int ringsel_modal (bContext *C, wmOperator *op, wmEvent *event) switch (event->type) { - case RIGHTMOUSE: case LEFTMOUSE: /* confirm */ // XXX hardcoded if (event->val == KM_RELEASE) { /* finish */ ED_region_tag_redraw(lcd->ar); - + ringsel_finish(C, op); ringsel_exit(C, op); return OPERATOR_FINISHED; } - + + ED_region_tag_redraw(lcd->ar); + break; + case RIGHTMOUSE: /* abort */ // XXX hardcoded + case ESCKEY: + if (event->val == KM_RELEASE) { + /* cancel */ + ED_region_tag_redraw(lcd->ar); + + return ringsel_cancel(C, op); + } + ED_region_tag_redraw(lcd->ar); break; case WHEELUPMOUSE: /* change number of cuts */ From 1cc79c1a95b76f36a4cc4f20ef508f122a40278f Mon Sep 17 00:00:00 2001 From: Martin Poirier Date: Sat, 10 Oct 2009 03:29:03 +0000 Subject: [PATCH 074/138] Fixing mixed code and declaration. PEOPLE, PLEASE CHECK YOUR WARNINGS BEFORE COMMIT --- source/blender/blenkernel/intern/mesh.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 391aa0ec32f..ce30075c424 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -996,6 +996,10 @@ void mesh_to_curve(Scene *scene, Object *ob) EdgeHash *eh = BLI_edgehash_new(); EdgeHash *eh_edge = BLI_edgehash_new(); + ListBase edges = {NULL, NULL}; + EdgeLink *edl; + + mf= mface; for (i = 0; i < totface; i++, mf++) { if (!BLI_edgehash_haskey(eh, mf->v1, mf->v2)) @@ -1014,9 +1018,6 @@ void mesh_to_curve(Scene *scene, Object *ob) } } - ListBase edges = {NULL, NULL}; - EdgeLink *edl; - med= medge; for(i=0; iv1, med->v2)) { @@ -1042,20 +1043,24 @@ void mesh_to_curve(Scene *scene, Object *ob) MEdge *med_current= ((EdgeLink *)edges.last)->edge; int startVert= med_current->v1; int endVert= med_current->v2; + int ok= TRUE; + + Nurb *nu; + BPoint *bp; + VertLink *vl; appendPolyLineVert(&polyline, startVert); totpoly++; appendPolyLineVert(&polyline, endVert); totpoly++; BLI_freelinkN(&edges, edges.last); totedges--; - int ok= TRUE; while(ok) { ok = FALSE; i= totedges; while(i) { + MEdge *ed= edl->edge; i-=1; edl= BLI_findlink(&edges, i); - MEdge *ed= edl->edge; if(ed->v1==endVert) { endVert = ed->v2; @@ -1092,8 +1097,6 @@ void mesh_to_curve(Scene *scene, Object *ob) } /* --- nurbs --- */ - Nurb *nu; - BPoint *bp; /* create new 'nurb' within the curve */ nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb"); @@ -1107,7 +1110,7 @@ void mesh_to_curve(Scene *scene, Object *ob) nu->bp= (BPoint *)MEM_callocN(sizeof(BPoint)*totpoly, "bpoints"); /* add points */ - VertLink *vl= polyline.first; + vl= polyline.first; for (i=0, bp=nu->bp; i < totpoly; i++, bp++, vl=vl->next) { VecCopyf(bp->vec, mverts[vl->index].co); bp->f1= SELECT; From d30be46ad8b13d8b641a4a67ffc37a1fad53be7b Mon Sep 17 00:00:00 2001 From: Matt Ebb Date: Sat, 10 Oct 2009 08:40:44 +0000 Subject: [PATCH 075/138] * icon set updates, thanks jendryzch --- release/datafiles/blenderbuttons | Bin 182512 -> 190499 bytes release/scripts/ui/buttons_scene.py | 2 +- release/scripts/ui/space_info.py | 12 +- .../editors/datafiles/blenderbuttons.c | 11660 ++++++++-------- source/blender/editors/include/UI_icons.h | 16 +- .../editors/space_graph/graph_header.c | 4 +- source/blender/makesrna/intern/rna_scene.c | 50 +- 7 files changed, 5997 insertions(+), 5747 deletions(-) diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons index 79d6138e3f03e8b9a805e383f9560da48d27daaa..aa7870f67122eea54bb6c6b0d471527a7f88c140 100644 GIT binary patch literal 190499 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

k>QY%x1k5Tv9@>Ti=o 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 a|&mG+bP`KrMfO#Se-L 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⁡pzEJ|aX+Oia%&%!$pWW*uA* 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 P00000NkvXXu0mjf9Uyta literal 182512 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 tEVGbFgd_)?a?i+I3k>uW~u8yF=kD3#{ zY&3$?7P-*+{dulEd>yHE!0&0!TaBI{*Dd!)o9+|b{xC$%M&!D^ZP{z?u}@4Mg5v*E z($&dEu`*rnSMXKWcewI*tHDAIT2;|un^I>8F+KVgu2%}F!Mc@3^{C$H`BJbOFp()6_qrNnW0*D ze`?fGxNyCHU#VSz%@WHo$5mEPK*$;S>G^w~F3P^Lz}aByFR_qc!yFcV3fycB5R^ZO zlEhje1Pwzyx7?++F?|ExUQ2u_<7AHI>JcZq9BW^UWM$>q$~^P^srGi zW559O`EhVLCTmn%p57oWbL!wt%P8rBtV=IX@*tE{V)z6(I5=LtdgW)3AN*gujD)r1 z9r&uZNG)rtnG}6*I{-}`;Ls0_VLISWY=6{&#wLcY2gHaTTyt!}t7}pcr zFBDo@g8DH#W&4- zZ}&EZ&|hYAxU97V9*R(M?nsZnO_2MUFo}{~&ZOn}X!4U@1_gO)qBZOgg<5}n53eq} zq1~Yn79Nf?B7nD!#(gV1mls=5$^8p zn$?{tA&qmalx&%5IMHw12@_f4URVDlFRo#YGq-+VJ8`vi#_1tMtreZSqj$A7HFc|A z#q7^FAW~FDxu%?^lLVwjK1LW#^AJm@1A)|n04@MXq?Lxf^eIcA7F!T(f&jjS)g0FU zy7}EKqQ<1x)jrFQAbMvLr1+`k&CFa{0E_#glB==J-DGsDUEq?PEf-^X(cHm)&Q#g> z(cj;js$zdku70BPNc`qUR+$2FRQ^4~Gaaoey_gcXR?2jR7SctY4h3%SWg3hM2nk)(=uc8( zS&vm}kH0vpyJ``csPLf{&6|4f(Bz{$8~iywo~I};JF)!@hImW$vG7~aoqK9)J<*M^6v=s*ROl(fEYYwmGs_~gwH0>8FPku!z5!H^{Go5^ zw=`tFsAO49*HqhqIUjkblTP;Rl;yxf`=u1p&>+dCS5EjTJ7?(>A3*L1JYK{PY&xeqJ(P{_u?3_v!Hc|$N6ox)HC|#MM7FE*Idk_8$Wb~s+ zA-NEBzWj#?z-a6u6N{@pQu5_>fxw;R5Ds6k+<KeSJa9IMeUO+kTLo9q;{xJb!J~(i#0Q zS)hW1V))Od!|6(Ru=n7by#AVpmmbCSzJQ!^A!;K9`wzW%{BK)QhaZ{ys5qsOeW5}4 zJL^D5;au#Dl1_%~QxxQ&8BQyJ5C@@sGL+8mA(P1uY@69&e8hFIiKa}O)kVC2c0U|Y z2$flIE(S9u^TUTh;o-Pi(Ty-`hg8Hbm`3g}wiylU1Cq22p}2=dTAIC}%gWtJ_2lym4;9SRl#~5u{lzhYzN*DNb4d1pNfipCkQn5LEXy^mg7-P=)o>L(ka1O zT3Uj_68R08nd{&pb%ev3aH`95&=Y(O<2IzkwC(FYe9#uWO@X<--LenSk~LY%9HxDq zU{gL@^3WoYDws;sCe@$YKLxJeKRCM?Qle$sd1{i(3iinXnahecAYkqA%o=to@;oJG zJ=osDG_ogcjE$9fZ$=kzK97{8r^Q3dlzgbp%5{5cD17IGZ9FZ}sP4DT{o2ZH2fY5B zF(o{Qjr}pgn+`Yol?;mEsOgAEVoAlLV?67edbem+{qNsDe@J$Fs4Q>pa72G0xOdT< zbDGbggTfc6mB*6&~g0!`w#oyr_Y-2 zZ$EPKO~*Nmxm%LL+H>!#-Y7Shz5Twy(xu&x8z-mVb3Z-%P0DN2Kj#piT#z$+4%%fI zObm=TWJui$5Ct3Bo*1ape{Ey*Rqd_Bt-ZSVFd&M4PS*8UuZC=L-tpH`Mj?esA-^3M zg#OOW&DF+a^Wkg2HAOAr9ReP{5YW#5Md*3Rpj*1F`hD?+E^7yLTwOu^;gt`1+35V-OzxJLMXgC1{)-Knp*`l^)qt19W9+#1qu%=#0?$tA@Tw|1y^iW^trRR6dE z8ht9%nfN#=Ds>L6Y0|*_0hEIK0UfeKm6BJbgeX3G)u*L$zaG46HnlLLx>FX0S|RlA z&h~c?1zaw29DJ_u?OYRGnD?3DS&XI z3Yh%81qr4N+RP7?%!&B#-*t0;iOPTIGRRarVxVi#W{b1|vDNFjH{9UD!9jTsc^|kw zkpG}g6w1iYz%XCUt6_yv)~co=3BF$l`}lxi*7imC%W&;f_C?jLi(SK( zqwQSljUC)3fC+|!@8`>InI~p@huW#DPVP{Ku_6@})qCpjoTOjw2tPVWY_YS=Kjx`4 z9nvq3@KBRZ4Wn&=+x`piQVao~B$)3+tc`yE(9?bmxvfIb$O;CP$8VKRXa&k+J;9{C zDdz1txwqbalqvhgKUu}UQH54}{WF%4)~T!SoBG*D_Ia#(TCk1@Vb&c>+!J{O;iFl` z;xAtw&Ae|8774kJd%^!ld4vyvb;Ad`v(-l=E`iiecJicrHvJ|htL>J(qO)l=xwGfz zdu2h}>K>y%NW&Xb;LV0W>{2UrxXFldZiIz}De;!dC@bFrG7U5Wvkp?VY*dC|eSgW8 zd*9RHt9&3X0_Ju&B0thNZ;0g+WX8tF$D<~OLhwe*NNduAFf;XI0HI$Sw(JS+5J0Yb z{kDWHoL?KfWve%GO7IQw*SXT{`YcWFdp+c`crt2Dd8IjAWEXb}F)%vnISwkcN$5^G zNPnKXu!qaqV>rflkp~5G2(m&?!&|y`DhLfL|}Qyn5`G~(g&ccF*qHa(4<&vzFiuX=N{K!i2rdv zz17+&4t_b!AIN!jp1d00qJGQC*x>(u%7rYf3Rdx(|MU3h%e_sN_Dgf}^VUCKkvV~9 zuMk4i4vqlFYXXY;Ayd2}U#$Q|03nl?*ZDR}>T@hQ6On{#Mq%MMk&5Y6Dw8g^#P#k{ zQPo&#mvJEI61pQmi=!>eQhiDtX93?KS1a0;<%z3-G}7KAZ_WAbHVj+%`LpZ`UJuh5 zAqKGh=l?_oh+3jOXY<-kG<(czh)_mssmS9_F`--=a$m0!ij(8wh93cS${R2&XkhsZ z>05RD7=2UzL}bhj@?3t@z{K-leb|AN&g@BQNd_y$(9qB%umpK?bV|p{!1fBWczRaW zHqVZjUQmxJdclFUCd;PM&fflfC`;XT5VVbUU~3acM@50byna&z4b9xjN;wbUW}MV{ za&vMnY+%zxa_fqqD=p4OIzRg_I1M={b8~Wf4ME#ZX{@i`GHhc9aI(`NN^pLOcuPpc z7p|Ajh5GyZ&ogjpy;&zDL|k<~PFUGxC;x zBAUZ3w2w&rFyUZ3R%DGmmEuq4$s;`!yG)3h(f#&{7US7t1h-kDqmVb!K+cP z_u-3q{i}qK$sA;iju1i!Wxadq?Becj=sP_lDQiH1_z_IfL+ZABaSnZ!jn{;TpydS6=#P(6KU7QnV+k5p(5xbAL4zt zbghCfB)1LSxC*13HFUZkKJOczoNSs1weHoQKYtV;%>JK(C9lVHgea3p!uC^^QsztF zp9c96TozrO?#A<@Sq~bDj1%qNU?7ZRFfnpX6f`;l8MaedKKtD4Im4?X3i51OBdIl) z*5|KZ#QR7fMC{9&~RuXkK}uN6qz@JfM2as@AUzTGi1t~EMJxQY@M_3lHb|nZQgm0ieeFU?-L^!@r z0=3&0^`zM4b<%O~%lU2DH4q8g39-pc^XrIaedwL2c1s)Ps))W!mnARd!kD+2NM8jf4Ho z)FwYm>`Wd-YSD>4mYFZ>I`&t7IWe|U>VtNJg$l)G_G2+|x-ks3TH(vPtuM*CsI0fh zcUsM(S1{5=1#)M83Vh7k`6j(}PQN-%P2BQ)!GQ#3CNf%Dzts@*WbC0kfCHWr zXi~`N00)I-%x$8x+MblJ0#H4W#4Iwje>Z?4jEHx zZ)^KqhNU#uM1Ty8*%n8Th8F`D>py6a0KMcdXjV?41JO^9D1I-;^zU&e1h7kMMbrP5 z4aN;ebKGn;V&-OZ+Q)%84egiKlmNoprrq)8qfKC#rW0#z*}kX1frG1XWy7t5g^sE! z9#W1I_Yi4;M1Y9i2j(NPVE2S{P`X+>3YxcKwDbWxA9@E`&;wF)s`c)dMz*K$vYBt9 z)Wx_`#QI&tpMD`UX`kQa1#_3k?5@W+7TwM5WH~JC`vGi_>t}g+aX|zpa8L0TB5_$O zS8i-N`q*b~K0p9GhnC_rD3+Y50lvCc4RRx4@Ly|U(G?wg@&XN(7spn&}4-*u?P6Cm| zSRjuFzGip<6yrCcelL-a^DY*iXL`1A(pi2hjlj^RaB)L{>Q7`CULcmf7Xi<9Pqi;* zI9dBAC5#lDNiPVl+6UCG4!y`wkMkx-R&=uU)h-J%Bc6BI zGSdio_<_)j7D%ul4LGxUNlhmSkh~%~e`IktBk}&D;t(9W=LWA&T7Oc2 z(`5esi=W;=hkPmw#@=Y@HF+>~toB=;0ceE~(#3$Q&kTn3_{kKx+v`A2e=Y#;q+X?q z^-a13gde~Bs^GGUskR1Vl>FOwp9$1+YwTX?B$k(xdoMg?B;r8Wp^%?1vJi(i!Zb!j znvRGwOi3#xNF~!>`bJ3ShNoB(55kl(eIK@tgV(|(I_zq!B=8Tg`Qep;`Ws6m;Srh< z25q_uN2FS}X+U_5e!0a%#18o^{p}1b)1h5SmCNav{07(%$&NP1mzNh81Ix?#;dpf( zL?}+7Bu}C~@Rq1Vnsf5FJD_cCcjTPo)#o3i!JAm*vNO~$j@d18$Ne^Ht z1R?Tjmw9+#C{zJ+&!L%((c)t)I%9R~=9Ptofyt>UAK1?_Qwz_DNk~}w`uo$N-$2Pj z!;)I!2(2ve=FhIKV*gSiU)$Ia`m8b*X+9dOZfzol<%oliUy6;3%b*a=h61!JR8Ryz z#zT86h5(__9;gr=h=+XP7!2h7nOn(g-Cw93{^@nci}Qr~I*K}m*E`s_8cac2EfV(E zv<5B>{|G6!-Smr1x~Mp$i%o}Lc3yhha6KRpkuli2E#Wk<$QIOG_o$%s`KAEA2fp}U zbQZ^3xjBDy$~ryWLb*t&)cLfK64N(_<~&|^lV)aAVixiscu;IY_q%QF4wGKs*GtRW`z9d`YyWV@Pd9y1a6dylca3p>5Glj{VKnhz3EyRkw4TpHDz!Obb@8?3f{aSzahmxTfc7ddk9DUUZ#)ex=J!w z0=CZw5$j0VgE!D#tNHa62TD5v1TxON9&8=9s`6Y|bc(>oYwQPfe#?EuA1(dshmqbQ z2}I&cs`ASM zfAhPX$VzH$Z4C!e39HZ^4+TDRY7mGgT;bSaH#0k1UtV7R>==fipo542ciMK2_>(7H zs^d;ujisKBp|xm!&LM_fy%qR8?8~I;m0Jt^FW8%|>^ISa-vDF92bu!pJT}Cz9R$PV z(+d`WH3dX__Ri-h0e=1o?Fy$<2cWY!0tsVds+tnIK0RI@9y*N-6E<;qz;W=KlD(o->mkfUIJ6}>qDKAj7?CdN~37$f7suK zRT~!}2CNyRIP~VWDM%UVZEe?00TXUJ1L$Q~clkB|z{nvkD=43-ye};vAaDgYBnHHQ z+Z;IZP<$9{iDdYOc-&@G$TrSTON#))N&|dpc6nJdAFiEs0CELDB~V&eT3Y%jUhmHy z8E(RMZ>j=WJw#q(Ban7in1F=Cj9?yCIuKuhi^2*RY|QuWHKK{7Vuasn4|3h^8$Hbv7!?ml>)>%rH7KPBH z?w2(D`Klxl2*0Z3qa62w=(6m)@)IHb%2f3^A2bL_z-IRgs&nw3f>p$V z2oeboJXnON9|f9g=L5*f6bN0Q+_?w5nV%XqMORLVpqi2bM4D^3;qQ$?>WP@d0wsKi zPg`krSNdV_{&1a7?EaTqh`%s$n}ubbud=+{1)wf#hj}G%5@w?kbhB%Lb&y?QOrJ$L zgLrx8@b&F3YTgm)NC0*#rkuLizHtX z5+Z*5pt1m%x#``zcRLBFg(LyNjM#w`<3MF-LMYvSr^b{X_cM&L zLyw7Ra4_8Y^Y7d520q)1-R0xI`MToy#Isxr&6L!84N5p+PkarT@Sw9+h)kM+cxt49 zOb+e{(Qart!D-O&wz!6xanU#pjC8ivAvzo?CmV>UIcN9tM-b)dRj8OkZKDsO!YVUJ zkNOP0C@;uD^Sa^p=>17z4B*7Y*mTSAfK9UToJH8+s9FkZwGys5XCz(;rW?(ggFv!= z1`z@^>m!8>@PzN+Mg&%a3lW_eNh)_X#Znloga2_Wm$tUHw8~%6)toL-+QAii3gEnB zBJtOE`rC&=jRWUc6QD#Lz{I~onw+zJyXO33jHX8EP6Ae}8XGAeV7!o_L;)~8FaliN z&hGA06%``zl->6_JFuof=)PzB){&c=3nPD&w_<*9mYsud0IJ1;;$jH{gQ@H>bddyy zmuA*vMyBQ;--np({E{)Ur_}TKfuH*^FuwFgA7@`Lf87m==lDu(6g;;>LYmRT?x`#g zThN`hHrnMr73SP-9F#;9WDS}uOlDhd9bKjb>MIvMz%r+N>z|CHCeX7oZqTvFAZ`w7 z6bXWedyg_ugMU^9XvH&NnkK$?gB_*+I0)bCmX?uY}?sdU_!V z%w`+ZWMpLf72(le%I(fr{Q5v=@!Q0f<3Sf=p$J(ve&Vd|M$ipi(W9?3k6Et0YE@EV}4QW-9pWSC8S z3I{!4A|<(+E9mIxR7UnX!~*l{14shNKtg|G_3*XOo3n#c8sCe0aKjqG{iapxBMiht zv>@X%wR^d+mwu9EM1J4|1i?DF|1)q!iD>o@47>qr35p+uyRR57u>cl2-U(iKMu4}K zD;uLYHM%#d5-F(@3L`x=xwsYsPo!Z^plpj6E%7aB2M-c@vl9%M#?bRxn8*f9#7t1p z@V~o(!1!nAwOYfDlhSK7^?>dgztcUSQ#6ZGOG&8?aJoU6;OcjGApBfh7;!V2{&A|g2}GlU z!54YH35UtpiyNs~qolfAHjvrubGFJfRb<{?14TnDOcKXy7jeHE zlXfJC)*>6E02}p#9rtPeutP2Ux(E#bHrRG$7>QbyZr{EQipc9BkW?0d(lPMXFxMmK zPrS6W#Dt|6VETW%^32+XfiZ@Tjtc?EF&CSi@mq7BR6Np!| zFq7Q4=l3n(Qz`WGFS6i32>y@~Rc2y0PHhkt-xVx?feVBpNfZ15Ez}Ft9mW7Hkh?QX zwzbK}=%`&}S^oOeow&;9{^`3Wf|8Ol1{#@aY1#r^gSYbCRM%N(?90nt+ew`fGaTq; zOX3h8O$YcyZEbBMatt`Db%(f!+}Qa_I5z-W-Ho)gG$ZG*NZph-xj01`vM3+`f#<6! z75LlM)&{$z!(_Q*a(-qei$g=mEmBA_usV9kb^lAN$9ITonuNuV9X8=js5|zrH9a$3 zTKts(`-c5lmhoiqo1p<>MEh*N2BaQc)cmg!yJ0)J0CN*hW=YmgyeT7g;9oIOQBh<% z3gV`k)5#^^B@IWR5|w5AJR@Ir_{!C_5y}h1%#~nS1r4y0V6O9)aL%})!X4hU%PU}5 z?*m>M`1^)du%Zses=SUR?6ZLkqi=3o6D&yRx98_+CVpa6Ia z)b(B{r!H0HS6BO%*NN%OLZD9yoJh;hP2TG~fVsB;eimqWXyD9P!C6KE!7fi!xQ(c#ROW3oEPqv>2W|;* z;JojMVtr%73enCK?}1Kp#QtlQSNbb_Ld(nN3+)bB9~O?2r%NYR##)0 zxmRwjEC(&&+tAYKhpNh4cd)am*>Op$rfb+e@!FGZUy8?wZGUqy3&~UUlk1k&okGc445vo2 zY>yB*IOUr{=_qIe17Box0la(2t7ZksqCt%@=u9EY99$cwr(N_SB_$zwn*1y{4@a2D zr2C3oAK;wvwd1})w;}#l%0gr4fj>aNuo3Fm#-tZK@z7HI*>9@r zzzdR*0EfGM3fePge2jlTRh-pDe5r(hm5fXwngb+{F1$hy=zdi_s7PmlQR+JEB{xBX z_dYq90b+U4LCv}2Aq1$_87SiI;1OMj_R*qIkAF_-_kO9@?}xvS9Y)k<>`Vidd@Z$N zu%03q&6pjpF7D{-P3%)P9niA%yJQ`=y5d$*Y_4-#wdF6WQf}%F{4V*5Tdxup{AkZ{ z=|E0jUS;k^9wuFL@JFN0$pT}EerT$?#sU#+6&MPzS}W`6;c04Wf&_$0)Q1ZBA(&|& zG5gs%2*sc*Hs{6_$}1A z*IbmDqel`EtGl&51M7!|gyI*_5~+kK<)}6EFdnTBWG1sQGbd7f2J%zeMG-L zR`8oJY2N)_J(eoR+oEzp

%`*qV7s!p#G7t<%-jRbJQ@?=7)%?MGF#wYENm!!Wz= z_JL7=hD){1^9!pHo%C|DaC;#r2YHy zt27RJ;ifR_#Q*o$@C_(B$e%c+zjOK69IKbFU!PecaHpx9 z0#wfY2D!h9kw3_DjFJx{w(zebO@LULeWG30-Qle)UhBTBb&~VzmqgfjQ7Xqs%PsYJwoE2 zfZOi@D}CCoCAvp~_)HO3v6N)T7eV5Yd!z<-)>kCX&=G6{4E(P3ZhL z4$OWCxiK?6+-f9=QoJ0UR`0t0&MhinrENQoLyDkBB*6Zg7YA~WAP6h8hsJt4Mx<;B zP8}0Ma(m>_jBn;>;jL$)+f8-`kK^)%%O_;`e2Ft6+ForcYkkBrytBD=9{-M;KFd(6QK_^ z?Mu`ZjaDD?@xv4HgkyqVtI!l48yq|=0v}07+Y#J%x1n3dhIBz~t*nfsv96-en3