diff options
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/include/BPI_script.h | 1 | ||||
-rw-r--r-- | source/blender/python/BPY_interface.c | 3 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Draw.c | 91 | ||||
-rw-r--r-- | source/blender/python/api2_2x/Window.c | 94 | ||||
-rw-r--r-- | source/blender/python/api2_2x/doc/Theme.py | 5 | ||||
-rw-r--r-- | source/blender/python/api2_2x/windowTheme.c | 23 | ||||
-rw-r--r-- | source/blender/src/drawscript.c | 24 |
7 files changed, 167 insertions, 74 deletions
diff --git a/source/blender/include/BPI_script.h b/source/blender/include/BPI_script.h index 243e50ecfa4..80ac8b46900 100644 --- a/source/blender/include/BPI_script.h +++ b/source/blender/include/BPI_script.h @@ -47,6 +47,7 @@ typedef struct Script { void *py_draw; void *py_event; void *py_button; + void *py_browsercallback; void *py_globaldict; int flags, lastspace; diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index 912a479eef9..f79cb2065ec 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -527,6 +527,7 @@ int BPY_txt_do_python_Text( struct Text *text ) script->py_draw = NULL; script->py_event = NULL; script->py_button = NULL; + script->py_browsercallback = NULL; py_dict = CreateGlobalDictionary( ); @@ -756,6 +757,7 @@ int BPY_menu_do_python( short menutype, int event ) script->py_draw = NULL; script->py_event = NULL; script->py_button = NULL; + script->py_browsercallback = NULL; py_dict = CreateGlobalDictionary( ); @@ -915,6 +917,7 @@ void BPY_clear_script( Script * script ) Py_XDECREF( ( PyObject * ) script->py_draw ); Py_XDECREF( ( PyObject * ) script->py_event ); Py_XDECREF( ( PyObject * ) script->py_button ); + Py_XDECREF( ( PyObject * ) script->py_browsercallback ); dict = script->py_globaldict; diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c index 0c75ee22ab6..f6c5aff0db8 100644 --- a/source/blender/python/api2_2x/Draw.c +++ b/source/blender/python/api2_2x/Draw.c @@ -70,6 +70,11 @@ #include "interface.h" #include "mydevice.h" /*@ for all the event constants */ +/* these delimit the free range for button events */ +#define EXPP_BUTTON_EVENTS_OFFSET 1001 +#define EXPP_BUTTON_EVENTS_MIN 0 +#define EXPP_BUTTON_EVENTS_MAX 15382 /* 16384 - 1 - OFFSET */ + /* pointer to main dictionary defined in Blender.c */ extern PyObject *g_blenderdict; @@ -510,18 +515,6 @@ static void spacescript_do_pywin_buttons( SpaceScript * sc, void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, short val, char ascii ) { - static int menu_hack = 0; - - /* about menu_hack above: when a menu returns after an entry is chosen, - * two events are generated, the second one with val = 4. We don't want - * this second one to be passed to Python, because it can be confused with - * some event with same number defined by the script. - * What we do is set menu_hack to 1 if a button event occurs. - * Then if the next one is also a button event, w/ val = 4, we discard it. */ - - if( event != UI_BUT_EVENT || !val ) - menu_hack = 0; - if( event == QKEY && G.qual & ( LR_ALTKEY | LR_CTRLKEY ) ) { /* finish script: user pressed ALT+Q or CONTROL+Q */ Script *script = sc->script; @@ -533,27 +526,20 @@ void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, return; } - if( val ) { - if( uiDoBlocks( &curarea->uiblocks, event ) != UI_NOTHING ) - event = 0; - - if( event == UI_BUT_EVENT ) { - if( menu_hack && val == UI_RETURN_OK ) { /* "false" event? */ - if ( menu_hack == 2 ) /* was last event UI_RETURN_OUT? */ - spacescript_do_pywin_buttons( sc, UI_RETURN_OUT ); /* if so, send */ - menu_hack = 0; /* clear menu_hack */ - } - else if( val == UI_RETURN_OUT ) /* possible cancel */ - menu_hack = 2; - else { - menu_hack = 1; - spacescript_do_pywin_buttons( sc, val ); - } + if (val) { + + if (uiDoBlocks( &curarea->uiblocks, event ) != UI_NOTHING) event = 0; + if (event == UI_BUT_EVENT) { + /* check that event is in free range for script button events; + * read the comment before check_button_event() below to understand */ + if (val >= EXPP_BUTTON_EVENTS_OFFSET && val < 0x4000) + spacescript_do_pywin_buttons(sc, val - EXPP_BUTTON_EVENTS_OFFSET); + return; } } - /* Using the "event" main module var, used by scriptlinks, to pass the ascii + /* We use the "event" main module var, used by scriptlinks, to pass the ascii * value to event callbacks (gui/event/button callbacks are not allowed * inside scriptlinks, so this is ok) */ if( sc->script->py_event ) { @@ -756,6 +742,21 @@ static uiBlock *Get_uiBlock( void ) return uiGetBlock( butblock, curarea ); } +/* We restrict the acceptable event numbers to a proper "free" range + * according to other spaces in Blender. + * winqread***space() (space events callbacks) use short for events + * (called 'val' there) and we also translate by EXPP_BUTTON_EVENTS_OFFSET + * to get rid of unwanted events (check BPY_do_pywin_events above for + * explanation). This function takes care of that and proper checking: */ +static int check_button_event(int *event) { + if ((*event < EXPP_BUTTON_EVENTS_MIN) || + (*event > EXPP_BUTTON_EVENTS_MAX)) { + return -1; + } + *event += EXPP_BUTTON_EVENTS_OFFSET; + return 0; +} + static PyObject *Method_Button( PyObject * self, PyObject * args ) { uiBlock *block; @@ -768,6 +769,10 @@ static PyObject *Method_Button( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string, five ints and optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + block = Get_uiBlock( ); if( block ) @@ -790,6 +795,10 @@ static PyObject *Method_Menu( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string, six ints and optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); but->type = 1; but->val.asint = def; @@ -815,6 +824,10 @@ static PyObject *Method_Toggle( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError( PyExc_TypeError, "expected a string, six ints and optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); but->type = 1; but->val.asint = def; @@ -873,6 +886,10 @@ static PyObject *Method_Slider( PyObject * self, PyObject * args ) "expected a string, five ints, three PyObjects\n\ and optionally another int and string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); if( PyFloat_Check( inio ) ) { @@ -932,14 +949,18 @@ static PyObject *Method_Scrollbar( PyObject * self, PyObject * args ) if( !PyArg_ParseTuple( args, "iiiiiOOO|is", &event, &x, &y, &w, &h, &inio, &mino, &maxo, &realtime, &tip ) ) return EXPP_ReturnPyObjError( PyExc_TypeError, - "expected five ints, three PyObjects and optionally\n\ - another int and string as arguments" ); + "expected five ints, three PyObjects and optionally\n\ +another int and string as arguments" ); if( !PyNumber_Check( inio ) || !PyNumber_Check( inio ) || !PyNumber_Check( inio ) ) return EXPP_ReturnPyObjError( PyExc_AttributeError, "expected numbers for initial, min, and max" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); if( PyFloat_Check( inio ) ) @@ -995,6 +1016,10 @@ static PyObject *Method_Number( PyObject * self, PyObject * args ) "expected a string, five ints, three PyObjects and\n\ optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + but = newbutton( ); if( PyFloat_Check( inio ) ) { @@ -1045,6 +1070,10 @@ static PyObject *Method_String( PyObject * self, PyObject * args ) "expected a string, five ints, a string, an int and\n\ optionally another string as arguments" ); + if (check_button_event(&event) == -1) + return EXPP_ReturnPyObjError( PyExc_AttributeError, + "button event argument must be in the range [0, 16382]"); + if (len > (UI_MAX_DRAW_STR - 1)) { len = UI_MAX_DRAW_STR - 1; newstr[len] = '\0'; diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index 41a7ad7c910..236275742be 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -68,9 +68,6 @@ /* See Draw.c */ extern int EXPP_disable_force_draw; -/* Callback used by the file and image selector access functions */ -static PyObject *EXPP_FS_PyCallback = NULL; - /*****************************************************************************/ /* Python API function prototypes for the Window module. */ /*****************************************************************************/ @@ -453,24 +450,42 @@ static PyObject *M_Window_QRedrawAll( PyObject * self, PyObject * args ) static void getSelectedFile( char *name ) { - PyObject *callback; - PyObject *result; - - callback = EXPP_FS_PyCallback; - result = PyObject_CallFunction( EXPP_FS_PyCallback, "s", name ); - if ((!result) && (G.f & G_DEBUG)) { - fprintf(stderr, "BPy error: Callback call failed!\n"); + PyObject *pycallback; + PyObject *result; + Script *script; + + /* let's find the script that owns this callback */ + script = G.main->script.first; + while (script) { + if (script->flags & SCRIPT_RUNNING) break; + script = script->id.next; + } + + if (!script) { + if (curarea->spacetype == SPACE_SCRIPT) { + SpaceScript *sc = curarea->spacedata.first; + script = sc->script; + } + } + + pycallback = script->py_browsercallback; + + if (pycallback) { + result = PyObject_CallFunction( pycallback, "s", name ); + + if (!result) { + if (G.f & G_DEBUG) + fprintf(stderr, "BPy error: Callback call failed!\n"); + } + else Py_DECREF(result); + + if (script->py_browsercallback == pycallback) + script->py_browsercallback = NULL; + /* else another call to selector was made inside pycallback */ + + Py_DECREF(pycallback); } - Py_XDECREF(result); - /* Catch changes of EXPP_FS_PyCallback during the callback call - * due to calls to Blender.Window.FileSelector or - * Blender.Window.ImageSelector inside the python callback. */ - if (callback == EXPP_FS_PyCallback) { - Py_DECREF(EXPP_FS_PyCallback); - EXPP_FS_PyCallback = NULL; - } else { - Py_DECREF(callback); - } + return; } @@ -480,6 +495,7 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) char *filename = G.sce; SpaceScript *sc; Script *script = NULL; + PyObject *pycallback = NULL; int startspace = 0; if (during_scriptlink()) @@ -490,13 +506,13 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError(PyExc_RuntimeError, "the file selector is not available in background mode"); - if((!PyArg_ParseTuple( args, "O|ss", &EXPP_FS_PyCallback, &title, &filename)) - || (!PyCallable_Check(EXPP_FS_PyCallback))) + if((!PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename)) + || (!PyCallable_Check(pycallback))) return EXPP_ReturnPyObjError( PyExc_AttributeError, "\nexpected a callback function (and optionally one or two strings) " "as argument(s)" ); - Py_XINCREF(EXPP_FS_PyCallback); + Py_INCREF(pycallback); /* trick: we move to a spacescript because then the fileselector will properly * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the @@ -527,6 +543,12 @@ static PyObject *M_Window_FileSelector( PyObject * self, PyObject * args ) script->flags |= SCRIPT_FILESEL; + /* clear any previous callback (nested calls to selector) */ + if (script->py_browsercallback) { + Py_DECREF((PyObject *)script->py_browsercallback); + } + script->py_browsercallback = pycallback; + activate_fileselect( FILE_BLENDER, title, filename, getSelectedFile ); Py_INCREF( Py_None ); @@ -539,6 +561,7 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) char *filename = G.sce; SpaceScript *sc; Script *script = NULL; + PyObject *pycallback = NULL; int startspace = 0; if (during_scriptlink()) @@ -549,14 +572,13 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) return EXPP_ReturnPyObjError(PyExc_RuntimeError, "the image selector is not available in background mode"); - if( !PyArg_ParseTuple( args, "O|ss", &EXPP_FS_PyCallback, &title, &filename ) - || (!PyCallable_Check(EXPP_FS_PyCallback))) - return ( EXPP_ReturnPyObjError - ( PyExc_AttributeError, - "\nexpected a callback function (and optionally one or two strings) " - "as argument(s)" ) ); + if( !PyArg_ParseTuple( args, "O|ss", &pycallback, &title, &filename ) + || (!PyCallable_Check(pycallback))) + return EXPP_ReturnPyObjError ( PyExc_AttributeError, + "\nexpected a callback function (and optionally one or two strings) " + "as argument(s)" ); - Py_XINCREF(EXPP_FS_PyCallback); + Py_INCREF(pycallback); /* trick: we move to a spacescript because then the fileselector will properly * unset our SCRIPT_FILESEL flag when the user chooses a file or cancels the @@ -586,6 +608,11 @@ static PyObject *M_Window_ImageSelector( PyObject * self, PyObject * args ) } script->flags |= SCRIPT_FILESEL; /* same flag as filesel */ + /* clear any previous callback (nested calls to selector) */ + if (script->py_browsercallback) { + Py_DECREF((PyObject *)script->py_browsercallback); + } + script->py_browsercallback = pycallback; activate_imageselect( FILE_BLENDER, title, filename, getSelectedFile ); @@ -610,12 +637,11 @@ static PyObject *M_Window_DrawProgressBar( PyObject * self, PyObject * args ) if( !PyArg_ParseTuple( args, "fs", &done, &info ) ) return ( EXPP_ReturnPyObjError( PyExc_AttributeError, - "expected a float and a string as arguments" ) ); + "expected a float and a string as arguments" ) ); - if( !G.background ) - retval = progress_bar( done, info ); + retval = progress_bar( done, info ); - curarea = sa; + areawinset(sa->win); return Py_BuildValue( "i", retval ); } diff --git a/source/blender/python/api2_2x/doc/Theme.py b/source/blender/python/api2_2x/doc/Theme.py index e2e9c74c8ed..d8be2074741 100644 --- a/source/blender/python/api2_2x/doc/Theme.py +++ b/source/blender/python/api2_2x/doc/Theme.py @@ -183,6 +183,11 @@ class Theme: @cvar face_select: theme rgba var. @cvar face_dot: theme rgba var. @cvar normal: theme rgba var. + @cvar syntaxl: theme rgba var. + @cvar syntaxn: theme rgba var. + @cvar syntaxb: theme rgba var. + @cvar syntaxv: theme rgba var. + @cvar syntaxc: theme rgba var. @type vertex_size: int @cvar vertex_size: size of the vertices dots on screen in the range [1, 10]. @type facedot_size: int diff --git a/source/blender/python/api2_2x/windowTheme.c b/source/blender/python/api2_2x/windowTheme.c index 5f2e06024da..7ee6cd80a1c 100644 --- a/source/blender/python/api2_2x/windowTheme.c +++ b/source/blender/python/api2_2x/windowTheme.c @@ -134,9 +134,9 @@ static void ThemeSpace_dealloc( BPy_ThemeSpace * self ) else if (!strcmp(name, #attr))\ attrib = charRGBA_New(&tsp->attr[0]); -/* Example: ELSEIF_TSP_RGBA(outline) becomes: +/* Example: ELSEIF_TSP_RGBA(back) becomes: * else if (!strcmp(name, "back") - * attr = charRGBA_New(&tsp->back[0]) + * attrib = charRGBA_New(&tsp->back[0]) */ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) @@ -146,7 +146,7 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) if( !strcmp( name, "theme" ) ) attrib = PyString_FromString( self->theme->name ); - ELSEIF_TSP_RGBA( back ) + ELSEIF_TSP_RGBA( back ) ELSEIF_TSP_RGBA( text ) ELSEIF_TSP_RGBA( text_hi ) ELSEIF_TSP_RGBA( header ) @@ -169,19 +169,26 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) ELSEIF_TSP_RGBA( face_select ) ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) + ELSEIF_TSP_RGBA( syntaxl ) + ELSEIF_TSP_RGBA( syntaxn ) + ELSEIF_TSP_RGBA( syntaxb ) + ELSEIF_TSP_RGBA( syntaxv ) + ELSEIF_TSP_RGBA( syntaxc ) else if( !strcmp( name, "vertex_size" ) ) attrib = Py_BuildValue( "i", tsp->vertex_size ); else if( !strcmp( name, "facedot_size" ) ) attrib = Py_BuildValue( "i", tsp->facedot_size ); else if( !strcmp( name, "__members__" ) ) - attrib = Py_BuildValue( "[ssssssssssssssssssssssssss]", "theme", + attrib = Py_BuildValue( "[sssssssssssssssssssssssssssssss]", "theme", "back", "text", "text_hi", "header", "panel", "shade1", "shade2", "hilite", "grid", "wire", "select", "active", "transform", "vertex", "vertex_select", "edge", "edge_select", "edge_seam", "edge_facesel", "face", "face_select", - "face_dot", "normal", "vertex_size", "facedot_size" ); + "face_dot", "normal", + "syntaxl", "syntaxn", "syntaxb", "syntaxv", "syntaxc", + "vertex_size", "facedot_size" ); if( attrib != Py_None ) return attrib; @@ -199,7 +206,6 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, if( !strcmp( name, "back" ) ) attrib = charRGBA_New( &tsp->back[0] ); - ELSEIF_TSP_RGBA( back ) ELSEIF_TSP_RGBA( text ) ELSEIF_TSP_RGBA( text_hi ) ELSEIF_TSP_RGBA( header ) @@ -222,6 +228,11 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, ELSEIF_TSP_RGBA( face_select ) ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) + ELSEIF_TSP_RGBA( syntaxl ) + ELSEIF_TSP_RGBA( syntaxn ) + ELSEIF_TSP_RGBA( syntaxb ) + ELSEIF_TSP_RGBA( syntaxv ) + ELSEIF_TSP_RGBA( syntaxc ) else if( !strcmp( name, "vertex_size" ) ) { int val; diff --git a/source/blender/src/drawscript.c b/source/blender/src/drawscript.c index c4ec1a4db3a..30c3e11f00b 100644 --- a/source/blender/src/drawscript.c +++ b/source/blender/src/drawscript.c @@ -85,13 +85,14 @@ void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent * void drawscriptspace(ScrArea *sa, void *spacedata) { SpaceScript *sc = curarea->spacedata.first; + Script *script = NULL; glClearColor(0.6, 0.6, 0.6, 1.0); glClear(GL_COLOR_BUFFER_BIT); myortho2(-0.5, curarea->winrct.xmax-curarea->winrct.xmin-0.5, -0.5, curarea->winrct.ymax-curarea->winrct.ymin-0.5); if (!sc->script) { - Script *script = G.main->script.first; + script = G.main->script.first; while (script) { @@ -105,7 +106,16 @@ void drawscriptspace(ScrArea *sa, void *spacedata) if (!sc->script) return; - BPY_spacescript_do_pywin_draw(sc); + script = sc->script; + + if (script->py_draw) { + BPY_spacescript_do_pywin_draw(sc); + } + /* quick hack for 2.37a for scripts that call the progress bar inside a + * file selector callback, to show previous space after finishing, w/o + * needing an event */ + else if (!script->flags && !script->py_event && !script->py_button) + addqueue(curarea->win, MOUSEX, 0); } void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt) @@ -117,7 +127,15 @@ void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent * Script *script = sc->script; if (script) { - BPY_spacescript_do_pywin_event(sc, event, val, ascii); + if (script->py_event || script->py_button) + BPY_spacescript_do_pywin_event(sc, event, val, ascii); + + /* for file/image sel scripts: if user leaves file/image selection space, + * this frees the script (since it can't be accessed anymore): */ + else if (script->flags == SCRIPT_FILESEL) { + script->flags = 0; + script->lastspace = SPACE_SCRIPT; + } if (!script->flags) {/* finished with this script, let's free it */ if (script->lastspace != SPACE_SCRIPT) |