diff options
36 files changed, 820 insertions, 131 deletions
diff --git a/source/blender/blenkernel/BKE_bad_level_calls.h b/source/blender/blenkernel/BKE_bad_level_calls.h index c500af345d9..561634335c0 100644 --- a/source/blender/blenkernel/BKE_bad_level_calls.h +++ b/source/blender/blenkernel/BKE_bad_level_calls.h @@ -58,8 +58,11 @@ void build_seqar(struct ListBase *seqbase, struct Sequence ***seqar, int *totse struct ID; struct Script; +struct Text; void BPY_do_pyscript (struct ID *id, short int event); void BPY_clear_script (struct Script *script); +void BPY_free_compiled_text (struct Text *text); +void BPY_free_screen_spacehandlers (struct bScreen *sc); /* writefile.c */ struct Oops; diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index b0904385a33..ae9929b9a2a 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -164,7 +164,7 @@ typedef struct Global { #define G_VERTEXPAINT 1024 #define G_ALLEDGES 2048 #define G_DEBUG 4096 -#define G_SCENESCRIPT 8192 +#define G_DOSCRIPTLINKS (1 << 13) /* #define G_PROPORTIONAL 16384 removed! so can be used later for other stuff */ #define G_WEIGHTPAINT 32768 #define G_TEXTUREPAINT 65536 diff --git a/source/blender/blenkernel/bad_level_call_stubs/stubs.c b/source/blender/blenkernel/bad_level_call_stubs/stubs.c index 894ac8fc6fb..1ced9b6430a 100644 --- a/source/blender/blenkernel/bad_level_call_stubs/stubs.c +++ b/source/blender/blenkernel/bad_level_call_stubs/stubs.c @@ -78,6 +78,7 @@ void mainqenter (unsigned short event, short val){} void BPY_do_pyscript(ID *id, short int event){} void BPY_clear_script(Script *script){} void BPY_free_compiled_text(struct Text *text){} +void BPY_free_screen_spacehandlers (struct bScreen *sc){} /* writefile.c */ /* struct Oops; */ diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 3d91636cda5..cc47169a7a2 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -326,15 +326,14 @@ static void setup_app_data(BlendFileData *bfd, char *filename) G.scene= G.main->scene.first; G.curscreen->scene= G.scene; } - + /* special cases, override loaded flags: */ if (G.f & G_DEBUG) bfd->globalf |= G_DEBUG; else bfd->globalf &= ~G_DEBUG; - if (G.f & G_SCENESCRIPT) bfd->globalf |= G_SCENESCRIPT; - else bfd->globalf &= ~G_SCENESCRIPT; + if (!(G.f & G_DOSCRIPTLINKS)) bfd->globalf &= ~G_DOSCRIPTLINKS; G.f= bfd->globalf; - + /* check posemode */ for(base= G.scene->base.first; base; base=base->next) { ob= base->object; @@ -358,7 +357,7 @@ static void setup_app_data(BlendFileData *bfd, char *filename) /* baseflags */ set_scene_bg(G.scene); - if (G.f & G_SCENESCRIPT) { + if (G.f & G_DOSCRIPTLINKS) { /* there's an onload scriptlink to execute in screenmain */ mainqenter(ONLOAD_SCRIPT, 1); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 69f21018562..21544b73f7f 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1365,7 +1365,7 @@ void where_is_object_time(Object *ob, float ctime) solve_constraints (ob, TARGET_OBJECT, NULL, ctime); if(ob->scriptlink.totscript && !during_script()) { - BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW); + if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript((ID *)ob, SCRIPT_REDRAW); } /* set negative scale flag in object */ diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 857fbc7586a..671b2887ab5 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -361,7 +361,9 @@ void set_scene_bg(Scene *sce) do_all_ipos(); /* layers/materials */ - BPY_do_all_scripts(SCRIPT_FRAMECHANGED); + /* do we need FRAMECHANGED in set_scene? */ + if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED); + do_all_keys(); #ifdef __NLA do_all_actions(NULL); diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 06b7d171308..59bfa17472e 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -50,7 +50,8 @@ void free_screen(bScreen *sc) { unlink_screen(sc); - + + BPY_free_screen_spacehandlers(sc); BLI_freelistN(&sc->vertbase); BLI_freelistN(&sc->edgebase); BLI_freelistN(&sc->areabase); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index d46742a6328..2455ebb98d5 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -73,7 +73,8 @@ A text should relate to a file as follows - TXT_ISEXT - should always be set if the Text is not to be written into the .blend TXT_ISSCRIPT - should be set if the user has designated the text - as a script. + as a script. (NEW: this was unused, but now it is needed by + space handler script links (see header_view3d.c, for example) ->>> see also: /makesdna/DNA_text_types.h diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index bea8e21e146..d9f6251722c 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2623,6 +2623,9 @@ static void lib_link_screen(FileData *fd, Main *main) sa->full= newlibadr(fd, sc->id.lib, sa->full); + /* space handler scriptlinks */ + lib_link_scriptlink(fd, &sc->id, &sa->scriptlink); + for (sl= sa->spacedata.first; sl; sl= sl->next) { if(sl->spacetype==SPACE_VIEW3D) { View3D *v3d= (View3D*) sl; @@ -2955,6 +2958,9 @@ static void direct_link_screen(FileData *fd, bScreen *sc) sa->uiblocks.first= sa->uiblocks.last= NULL; + /* space handler scriptlinks */ + direct_link_scriptlink(fd, &sa->scriptlink); + sa= sa->next; } } @@ -3132,7 +3138,6 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID case ID_SEQ: str= "ID_SEQ"; break; case ID_AR: str= "ID_AR"; break; case ID_AC: str= "ID_AC"; break; - case ID_SCRIPT: str= "ID_SCRIPT"; break; } /* read all data */ while(bhead && bhead->code==DATA) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 504e96ac78b..8ade6df7b4c 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1208,6 +1208,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase) pa= pa->next; } + /* space handler scriptlinks */ + write_scriptlink(wd, &sa->scriptlink); + sl= sa->spacedata.first; while(sl) { if(sl->spacetype==SPACE_VIEW3D) { diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 739bf7870ff..cd90c24b882 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -108,6 +108,8 @@ typedef struct ScrArea { short headbutlen, headbutofs; short cursor, flag; + ScriptLink scriptlink; + ListBase spacedata; ListBase uiblocks; ListBase panels; diff --git a/source/blender/makesdna/DNA_scriptlink_types.h b/source/blender/makesdna/DNA_scriptlink_types.h index 4983fa1d9dd..8a08d3f12c1 100644 --- a/source/blender/makesdna/DNA_scriptlink_types.h +++ b/source/blender/makesdna/DNA_scriptlink_types.h @@ -56,10 +56,22 @@ typedef struct ScriptLink { #define SCRIPT_ONLOAD 2 #define SCRIPT_REDRAW 4 #define SCRIPT_ONSAVE 8 +#define SCRIPT_RENDER 16 +/* POSTRENDER is not meant for the UI, it simply calls the + * RENDER script links for clean-up actions */ +#define SCRIPT_POSTRENDER 32 + +/* **************** SPACE HANDLERS ********************* */ +/* these are special scriptlinks that can be assigned to + * a given space in a given ScrArea to: + * - (EVENT type) handle events sent to that space; + * - (DRAW type) draw on the space after its own drawing function finishes + */ +#define SPACEHANDLER_VIEW3D_EVENT 1 +#define SPACEHANDLER_VIEW3D_DRAW 2 + #ifdef __cplusplus } #endif - #endif - diff --git a/source/blender/makesdna/DNA_text_types.h b/source/blender/makesdna/DNA_text_types.h index 391142db302..ea3ce237909 100644 --- a/source/blender/makesdna/DNA_text_types.h +++ b/source/blender/makesdna/DNA_text_types.h @@ -72,8 +72,8 @@ typedef struct Text { #define TXT_ISTMP 0x0002 #define TXT_ISMEM 0x0004 #define TXT_ISEXT 0x0008 -#define TXT_ISSCRIPT 0x0010 +#define TXT_ISSCRIPT 0x0010 /* used by space handler scriptlinks */ #define TXT_READONLY 0x0100 -#define TXT_FOLLOW 0x0200 // always follow cursor (console) +#define TXT_FOLLOW 0x0200 /* always follow cursor (console) */ #endif diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index dbf464de019..97e8819c77a 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -23,7 +23,7 @@ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * - * The Original Code is: source/blender/bpyton/include/BPY_extern.h + * The Original Code was in: source/blender/bpython/include/BPY_extern.h * * Contributor(s): Michel Selten, Willian P. Germano, Chris Keith * @@ -32,16 +32,16 @@ extern char bprogname[]; /* holds a copy of argv[0], from creator.c */ -struct Text; /* defined in DNA_text_types.h */ -struct ID; /* defined in DNA_ID.h */ -struct ScriptLink; /* defined in DNA_scriptlink_types.h */ -struct ListBase; /* defined in DNA_listBase.h */ -struct SpaceText; /* defined in DNA_space_types.h */ -struct SpaceScript; /* defined in DNA_space_types.h */ -struct Script; /* defined in BPI_script.h */ -/* -struct _object; // forward declaration for PyObject ! -*/ +struct Text; /* defined in DNA_text_types.h */ +struct ID; /* DNA_ID.h */ +struct ScriptLink; /* DNA_scriptlink_types.h */ +struct ListBase; /* DNA_listBase.h */ +struct SpaceText; /* DNA_space_types.h */ +struct SpaceScript; /* DNA_space_types.h */ +struct Script; /* BPI_script.h */ +struct ScrArea; /* DNA_screen_types.h */ +struct bScreen; /* DNA_screen_types.h */ + #ifdef __cplusplus extern "C" { #endif @@ -49,16 +49,18 @@ extern "C" { void BPY_start_python( int argc, char **argv ); void BPY_end_python( void ); void BPY_post_start_python( void ); + void init_syspath( int first_time ); + void syspath_append( char *dir ); + int BPY_Err_getLinenumber( void ); const char *BPY_Err_getFilename( void ); -/* void BPY_Err_Handle(struct Text *text); */ + int BPY_txt_do_python_Text( struct Text *text ); int BPY_menu_do_python( short menutype, int event ); void BPY_run_python_script( char *filename ); void BPY_free_compiled_text( struct Text *text ); -/*void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */ + void BPY_clear_bad_scriptlinks( struct Text *byebye ); -/*void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */ int BPY_has_onload_script( void ); void BPY_do_all_scripts( short event ); int BPY_check_all_scriptlinks( struct Text *text ); @@ -66,18 +68,27 @@ extern "C" { void BPY_free_scriptlink( struct ScriptLink *slink ); void BPY_copy_scriptlink( struct ScriptLink *scriptlink ); + int BPY_is_spacehandler(struct Text *text, char spacetype); + int BPY_del_spacehandler(struct Text *text, struct ScrArea *sa); + int BPY_add_spacehandler(struct Text *txt, struct ScrArea *sa,char spacetype); + int BPY_has_spacehandler(struct Text *text, struct ScrArea *sa); + void BPY_screen_free_spacehandlers(struct bScreen *sc); + int BPY_do_spacehandlers(struct ScrArea *sa, unsigned short event, + unsigned short space_event); + /* format importer hook */ int BPY_call_importloader( char *name ); -//int BPY_spacetext_is_pywin(struct SpaceText *st); void BPY_spacescript_do_pywin_draw( struct SpaceScript *sc ); void BPY_spacescript_do_pywin_event( struct SpaceScript *sc, - unsigned short event, short val ); + unsigned short event, short val, char ascii ); void BPY_clear_script( struct Script *script ); void BPY_free_finished_script( struct Script *script ); - void init_syspath( int first_time ); - void syspath_append( char *dir ); +/* void BPY_Err_Handle(struct Text *text); */ +/* void BPY_clear_bad_scriptlink(struct ID *id, struct Text *byebye); */ +/* void BPY_clear_bad_scriptlist(struct ListBase *, struct Text *byebye); */ +/* int BPY_spacetext_is_pywin(struct SpaceText *st); */ #ifdef __cplusplus } /* extern "C" */ diff --git a/source/blender/python/BPY_interface.c b/source/blender/python/BPY_interface.c index f0741ace86c..3306f68ccf8 100644 --- a/source/blender/python/BPY_interface.c +++ b/source/blender/python/BPY_interface.c @@ -43,6 +43,7 @@ #include <MEM_guardedalloc.h> #include <BLI_blenlib.h> /* for BLI_last_slash() */ +#include "BIF_gl.h" /* glPushAttrib, glPopAttrib for DRAW space handlers */ #include <BIF_interface.h> /* for pupmenu() */ #include <BIF_space.h> #include <BIF_screen.h> @@ -1062,6 +1063,8 @@ void BPY_do_pyscript( ID * id, short event ) PyString_FromString( event_to_name ( event ) ) ); + if (event == SCRIPT_POSTRENDER) event = SCRIPT_RENDER; + for( index = 0; index < scriptlink->totscript; index++ ) { if( ( scriptlink->flag[index] == event ) && ( scriptlink->scripts[index] != NULL ) ) { @@ -1103,6 +1106,249 @@ void BPY_do_pyscript( ID * id, short event ) } } +/* SPACE HANDLERS */ + +/* These are special script links that can be assigned to ScrArea's to + * (EVENT type) receive events sent to a given space (and use or ignore them) or + * (DRAW type) be called after the space is drawn, to draw anything on top of + * the space area. */ + +/* How to add space handlers to other spaces: + * - add the space event defines to DNA_scriptlink_types.h, as done for + * 3d view: SPACEHANDLER_VIEW3D_EVENT, for example; + * - add the new defines to Blender.SpaceHandler dictionary in Blender.c; + * - check space.c for how to call the event handlers; + * - check drawview.c for how to call the draw handlers; + * - check header_view3d.c for how to add the "Space Handler Scripts" menu. + * Note: DRAW handlers should be called with 'event = 0', chech drawview.c */ + +int BPY_has_spacehandler(Text *text, ScrArea *sa) +{ + ScriptLink *slink; + int index; + + if (!sa || !text) return 0; + + slink = &sa->scriptlink; + + for (index = 0; index < slink->totscript; index++) { + if (slink->scripts[index] && (slink->scripts[index] == (ID *)text)) + return 1; + } + + return 0; +} + +int BPY_is_spacehandler(Text *text, char spacetype) +{ + TextLine *tline = text->lines.first; + unsigned short type = 0; + + if (tline && (tline->len > 10)) { + char *line = tline->line; + + /* Expected format: # SPACEHANDLER.SPACE.TYPE + * Ex: # SPACEHANDLER.VIEW3D.DRAW + * The actual checks are forgiving, so slight variations also work. */ + if (line && line[0] == '#' && strstr(line, "HANDLER")) { + line++; /* skip '#' */ + + /* only done for 3D View right now, trivial to add for others: */ + switch (spacetype) { + case SPACE_VIEW3D: + if (strstr(line, "3D")) { /* VIEW3D, 3DVIEW */ + if (strstr(line, "DRAW")) type = SPACEHANDLER_VIEW3D_DRAW; + else if (strstr(line, "EVENT")) type = SPACEHANDLER_VIEW3D_EVENT; + } + break; + } + } + } + return type; /* 0 if not a space handler */ +} + +int BPY_del_spacehandler(Text *text, ScrArea *sa) +{ + ScriptLink *slink; + int i, j; + + if (!sa || !text) return -1; + + slink = &sa->scriptlink; + if (slink->totscript < 1) return -1; + + for (i = 0; i < slink->totscript; i++) { + if (text == (Text *)slink->scripts[i]) { + + for (j = i; j < slink->totscript - 1; j++) { + slink->flag[j] = slink->flag[j+1]; + slink->scripts[j] = slink->scripts[j+1]; + } + slink->totscript--; + /* like done in buttons_script.c we just free memory + * if all slinks have been removed -- less fragmentation, + * these should be quite small arrays */ + if (slink->totscript == 0) { + if (slink->scripts) MEM_freeN(slink->scripts); + if (slink->flag) MEM_freeN(slink->flag); + break; + } + } + } + return 0; +} + +int BPY_add_spacehandler(Text *text, ScrArea *sa, char spacetype) +{ + unsigned short handlertype; + + if (!sa || !text) return -1; + + handlertype = BPY_is_spacehandler(text, spacetype); + + if (handlertype) { + ScriptLink *slink = &sa->scriptlink; + void *stmp, *ftmp; + unsigned short space_event = SPACEHANDLER_VIEW3D_EVENT; + + /* extend slink */ + + stmp= slink->scripts; + slink->scripts= MEM_mallocN(sizeof(ID*)*(slink->totscript+1), + "spacehandlerscripts"); + + ftmp= slink->flag; + slink->flag= MEM_mallocN(sizeof(short*)*(slink->totscript+1), + "spacehandlerflags"); + + if (slink->totscript) { + memcpy(slink->scripts, stmp, sizeof(ID*)*(slink->totscript)); + MEM_freeN(stmp); + + memcpy(slink->flag, ftmp, sizeof(short)*(slink->totscript)); + MEM_freeN(ftmp); + } + + switch (spacetype) { + case SPACE_VIEW3D: + if (handlertype == 1) space_event = SPACEHANDLER_VIEW3D_EVENT; + else space_event = SPACEHANDLER_VIEW3D_DRAW; + break; + default: + break; + } + + slink->scripts[slink->totscript] = (ID *)text; + slink->flag[slink->totscript]= space_event; + + slink->totscript++; + slink->actscript = slink->totscript; + + } + return 0; +} + +int BPY_do_spacehandlers( ScrArea *sa, unsigned short event, + unsigned short space_event ) +{ + ScriptLink *scriptlink; + int retval = 0; + + if (!sa) return 0; + + scriptlink = &sa->scriptlink; + + if (scriptlink->totscript > 0) { + PyObject *dict; + PyObject *ret; + int index, during_slink = during_scriptlink(); + + /* invalid scriptlinks (new .blend was just loaded), return */ + if (during_slink < 0) return 0; + + /* tell we're running a scriptlink. The sum also tells if this script + * is running nested inside another. Blender.Load needs this info to + * avoid trouble with invalid slink pointers. */ + during_slink++; + disable_where_scriptlink( during_slink ); + + /* set globals in Blender module to identify space handler scriptlink */ + PyDict_SetItemString(g_blenderdict, "bylink", EXPP_incr_ret_True()); + /* unlike normal scriptlinks, here Blender.link is int (space event type) */ + PyDict_SetItemString(g_blenderdict, "link", PyInt_FromLong(space_event)); + /* note: DRAW space_events set event to 0 */ + PyDict_SetItemString(g_blenderdict, "event", PyInt_FromLong(event)); + + /* now run all assigned space handlers for this space and space_event */ + for( index = 0; index < scriptlink->totscript; index++ ) { + + /* for DRAW handlers: */ + if (event == 0) { + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + } + + if( ( scriptlink->flag[index] == space_event ) && + ( scriptlink->scripts[index] != NULL ) ) { + dict = CreateGlobalDictionary(); + ret = RunPython( ( Text * ) scriptlink->scripts[index], dict ); + ReleaseGlobalDictionary( dict ); + + if (!ret) { /* Failed execution of the script */ + BPY_Err_Handle( scriptlink->scripts[index]->name+2 ); + } else { + Py_DECREF(ret); + + /* an EVENT type (event != 0) script can either accept an event or + * ignore it: + * if the script sets Blender.event to None it accepted it; + * otherwise the space's event handling callback that called us + * can go on processing the event */ + if (event && (PyDict_GetItemString(g_blenderdict,"event") == Py_None)) + retval = 1; /* event was swallowed */ + } + + /* If a scriptlink has just loaded a new .blend file, the + * scriptlink pointer became invalid (see api2_2x/Blender.c), + * so we stop here. */ + if( during_scriptlink( ) == -1 ) { + during_slink = 1; + if (event == 0) glPopAttrib(); + break; + } + } + + /* for DRAW handlers: */ + if (event == 0) { + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); + } + + } + + disable_where_scriptlink( during_slink - 1 ); + + PyDict_SetItemString(g_blenderdict, "bylink", EXPP_incr_ret_False()); + PyDict_SetItemString(g_blenderdict, "link", EXPP_incr_ret(Py_None)); + PyDict_SetItemString(g_blenderdict, "event", PyString_FromString("")); + } + + /* retval: + * space_event is of type EVENT: + * 0 - event was returned, + * 1 - event was processed; + * space_event is of type DRAW: + * 0 always */ + + return retval; +} + /***************************************************************************** * Description: * Notes: @@ -1119,6 +1365,31 @@ void BPY_free_scriptlink( struct ScriptLink *slink ) return; } +void BPY_free_screen_spacehandlers(struct bScreen *sc) +{ + ScrArea *sa; + + for (sa = sc->areabase.first; sa; sa = sa->next) + BPY_free_scriptlink(&sa->scriptlink); +} + +static int CheckAllSpaceHandlers(Text *text) +{ + bScreen *screen; + ScrArea *sa; + ScriptLink *slink; + int fixed = 0; + + for (screen = G.main->screen.first; screen; screen = screen->id.next) { + for (sa = screen->areabase.first; sa; sa = sa->next) { + slink = &sa->scriptlink; + if (!slink->totscript) continue; + if (BPY_del_spacehandler(text, sa) == 0) fixed++; + } + } + return fixed; +} + static int CheckAllScriptsFromList( ListBase * list, Text * text ) { ID *id; @@ -1154,11 +1425,11 @@ int BPY_check_all_scriptlinks( Text * text ) fixed += CheckAllScriptsFromList( &( G.main->mat ), text ); fixed += CheckAllScriptsFromList( &( G.main->world ), text ); fixed += CheckAllScriptsFromList( &( G.main->scene ), text ); + fixed += CheckAllSpaceHandlers(text); return fixed; } - /***************************************************************************** * Description: * Notes: diff --git a/source/blender/python/api2_2x/Blender.c b/source/blender/python/api2_2x/Blender.c index e2f68a9a6f9..705b31e6ebc 100644 --- a/source/blender/python/api2_2x/Blender.c +++ b/source/blender/python/api2_2x/Blender.c @@ -57,6 +57,7 @@ #include <DNA_scene_types.h> #include <DNA_screen_types.h> /* for SPACE_VIEW3D */ #include <DNA_space_types.h> /* for SPACE_VIEW3D */ +#include <DNA_scriptlink_types.h> #include <DNA_userdef_types.h> #include <BKE_ipo.h> #include <blendef.h> @@ -64,6 +65,7 @@ #include "EXPP_interface.h" /* for bpy_gethome() */ #include "gen_utils.h" #include "modules.h" +#include "constant.h" #include "../BPY_extern.h" /* BPY_txt_do_python_Text */ #include "../BPY_menus.h" /* to update menus */ @@ -737,7 +739,7 @@ static PyObject * Blender_UpdateMenus( PyObject * self ) void M_Blender_Init( void ) { PyObject *module; - PyObject *dict, *smode; + PyObject *dict, *smode, *SpaceHandlers; g_blenderdict = NULL; @@ -746,6 +748,16 @@ void M_Blender_Init( void ) types_InitAll( ); /* set all our pytypes to &PyType_Type */ + SpaceHandlers = M_constant_New(); + if (SpaceHandlers) { + BPy_constant *d = (BPy_constant *)SpaceHandlers; + + constant_insert(d,"VIEW3D_EVENT",PyInt_FromLong(SPACEHANDLER_VIEW3D_EVENT)); + constant_insert(d,"VIEW3D_DRAW", PyInt_FromLong(SPACEHANDLER_VIEW3D_DRAW)); + + PyModule_AddObject(module, "SpaceHandlers", SpaceHandlers); + } + if (G.background) smode = PyString_FromString("background"); else diff --git a/source/blender/python/api2_2x/Draw.c b/source/blender/python/api2_2x/Draw.c index 4426c76218e..d122ed93ac5 100644 --- a/source/blender/python/api2_2x/Draw.c +++ b/source/blender/python/api2_2x/Draw.c @@ -70,6 +70,9 @@ #include "interface.h" #include "mydevice.h" /*@ for all the event constants */ +/* pointer to main dictionary defined in Blender.c */ +extern PyObject *g_blenderdict; + /*@ hack to flag that window redraw has happened inside slider callback: */ int EXPP_disable_force_draw = 0; @@ -505,7 +508,7 @@ static void spacescript_do_pywin_buttons( SpaceScript * sc, } void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, - short val ) + short val, char ascii ) { static int menu_hack = 0; @@ -546,9 +549,20 @@ void BPY_spacescript_do_pywin_event( SpaceScript * sc, unsigned short event, } } - if( sc->script->py_event ) + /* Using 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 ) { + int pass_ascii = 0; + if (ascii > 31 && ascii != 127) { + pass_ascii = 1; + PyDict_SetItemString(g_blenderdict, "event", PyInt_FromLong((long)ascii)); + } exec_callback( sc, sc->script->py_event, - Py_BuildValue( "(ii)", event, val ) ); + Py_BuildValue( "(ii)", event, val ) ); + if (pass_ascii) + PyDict_SetItemString(g_blenderdict, "event", PyString_FromString("")); + } } static PyObject *Method_Exit( PyObject * self, PyObject * args ) @@ -635,7 +649,7 @@ static PyObject *Method_Register( PyObject * self, PyObject * args ) script = sc->script; if( !script ) { return EXPP_ReturnPyObjError( PyExc_RuntimeError, - "Draw.Register: couldn't get pointer to script struct" ); + "Draw.Register can't be used inside script links" ); } } else sc->script = script; diff --git a/source/blender/python/api2_2x/Draw.h b/source/blender/python/api2_2x/Draw.h index 9f1d7eb19fe..27a80c23334 100644 --- a/source/blender/python/api2_2x/Draw.h +++ b/source/blender/python/api2_2x/Draw.h @@ -69,7 +69,7 @@ typedef struct _Button { */ void BPY_spacescript_do_pywin_draw( SpaceScript * sc ); void BPY_spacescript_do_pywin_event( SpaceScript * sc, - unsigned short event, short val ); + unsigned short event, short val, char ascii ); void BPY_free_compiled_text( Text * text ); PyObject *M_Draw_Init( void ); diff --git a/source/blender/python/api2_2x/Window.c b/source/blender/python/api2_2x/Window.c index 64ce039d063..3858647e179 100644 --- a/source/blender/python/api2_2x/Window.c +++ b/source/blender/python/api2_2x/Window.c @@ -1346,6 +1346,7 @@ PyObject *Window_Init( void ) constant_insert( d, "TEXT", PyInt_FromLong( SPACE_TEXT ) ); constant_insert( d, "NLA", PyInt_FromLong( SPACE_NLA ) ); constant_insert( d, "SCRIPT", PyInt_FromLong( SPACE_SCRIPT ) ); + constant_insert( d, "TIME", PyInt_FromLong( SPACE_TIME ) ); PyModule_AddObject( submodule, "Types", Types ); } diff --git a/source/blender/python/api2_2x/doc/API_intro.py b/source/blender/python/api2_2x/doc/API_intro.py index 9d54eac9d8a..91c00ce43b4 100644 --- a/source/blender/python/api2_2x/doc/API_intro.py +++ b/source/blender/python/api2_2x/doc/API_intro.py @@ -4,6 +4,8 @@ The Blender Python API Reference ================================ + An asterisk (*) means the module has been updated. + Top Module: ----------- @@ -17,7 +19,7 @@ The Blender Python API Reference - L{BGL} - L{Camera} (*) - L{Curve} (*) - - L{Draw} + - L{Draw} (*) - L{Effect} - L{Image} (*) - L{Ipo} @@ -47,11 +49,10 @@ The Blender Python API Reference Additional information: ----------------------- - - L{Misc facilities<API_related>}: + - L{Special features<API_related>}: - scripts: registering in menus, documenting, configuring (new); - - command line examples (new). - - (*) - marks updated. + - command line examples (new); + - script links (*), space handler script links (new). Introduction: ============= diff --git a/source/blender/python/api2_2x/doc/API_related.py b/source/blender/python/api2_2x/doc/API_related.py index 8326ee72279..e9d071ffb01 100644 --- a/source/blender/python/api2_2x/doc/API_related.py +++ b/source/blender/python/api2_2x/doc/API_related.py @@ -15,6 +15,10 @@ Introduction: - Command line mode is accessible with the '-P' and '-b' Blender options. - Registration allows scripts to become available from some pre-defined menus in Blender, like Import, Export, Wizards and so on. + - Script links are Blender Texts (scripts) executed when a particular event + (redraws, .blend file loading, saving, frame changed, etc.) occurs. Now + there are also "Space Handlers" to draw onto or get events from a given + space (only 3D View now) in some window. - Proper documentation data is used by the 'Scripts Help Browser' script to show help information for any registered script. Your own GUI can use this facility with the L{Blender.ShowHelp} function. @@ -25,9 +29,10 @@ Introduction: Command line usage: - ------------------- + =================== - B{Specifying scripts}: + Specifying scripts: + ------------------- The '-P' option followed either by: - a script filename (full pathname if not in the same folder where you run @@ -40,7 +45,8 @@ Introduction: # open Blender and execute the given script: blender -P script.py - B{Passing parameters}: + Passing parameters: + ------------------- To pass parameters to the script you can: - write them to a file before running Blender, then make your script parse that file; @@ -64,7 +70,8 @@ Introduction: myvar1=value1 myvar2=value2 mystr="some string data" blender -P script.py - B{Background mode}: + Background mode: + ---------------- In '-b' mode no windows will be opened: the program will run as a command line tool able to render stills and animations and execute any working Python @@ -108,9 +115,141 @@ Introduction: - an animation from frame 1 to 10: blender -b myfile.blend -s 1 -e 10 -a - Registering scripts: + Script links: + ============= + + Object script links: -------------------- + Users can link Blender Text scripts to some kinds of objects to have the script + code executed when specific events occur. For example, if a Camera has an + script link set to "FrameChanged", the script will be executed whenever the + current frame is changed. Links can either be manually added by users on the + Buttons window -> Scripts tab or created by another script (see, for example, + L{Object.addScriptLink<Object.Object.addScriptLink>}). + + These are the types which can be linked to scripts: + - Camera Data; + - Lamp Data; + - Materials; + - Objects; + - Scenes; + - Worlds. + + And these are the available event choices: + - Redraw; + - FrameChanged; + - Render; + - OnLoad (*); + - OnSave (*). + + (*) only available for scenes + + There are three L{Blender} module variables that script link authors should + be aware of: + - B{bylink}: True if the script is running as a script link; + - B{link}: the object the running script was linked to (None if this is + not a script link); + - B{event}: the event type, if the running script is being executed as a + script link. + + B{Important note about "Render" events}: + + Each "Render" script link is executed twice: before rendering and after, for + reverting changes and for possible clean up actions. Before rendering, + 'Blender.event' will be "Render" and after rendering it will be "PostRender". + + This is specially useful for script links that need to generate data only + useful while rendering, or in case they need to switch between two mesh data + objects, one meant for realtime display and the other, more detailed, for + renders. This pseudo-code is an example of how such scripts could be written:: + + import Blender + + if Blender.event == "Render": + # prepare for rendering + + elif Blender.event == "PostRender": + # revert changes / clean up for realtime display + + Space Handler script links: + --------------------------- + + This is a new kind of script linked to spaces in a given window. Right now + only the 3D View has the necessary hooks, but the plan is to add access to + other types, too. Just to clarify: in Blender, a screen is partitioned in + windows and each window can show any space. Spaces are: 3D View, Text Editor, + Scripts, Buttons, User Preferences, Oops, etc. + + Space handlers are texts in the Text Editor, like other script links, but they + need to have a special header to be recognized -- B{I{the first line in the + text file}} must inform 1) that they are space handlers; 2) the space they + belong to; 3) whether they are EVENT or DRAW handlers. + + Example header for a 3D View EVENT handler:: + + # SPACEHANDLER.VIEW3D.EVENT + + Example header for a 3D View DRAW handler:: + + # SPACEHANDLER.VIEW3D.DRAW + + EVENT space handler scripts are called by that space's event handling callback + in Blender. The script receives the event B{before} it is further processed + by the program. An EVENT handler script should check Blender.event (compare + it against L{Draw} events) and either: + - process it (then set Blender.event to None); + - ignore it. + + Setting C{Blender.event = None} tells Blender not to go on processing itself + the event, because it was grabbed by the script. + + Example:: + + # SPACEHANDLER.VIEW3D.EVENT + + import Blender + from Blender import DRAW + evt = Blender.event + + if evt == DRAW.LEFTMOUSE: + print "Swallowing the left mouse button press" + elif evt == DRAW.AKEY: + print "Swallowing an 'a' character" + else: + print "Let the 3D View itself process this event:", evt + return + + # if Blender should not process itself the passed event: + Blender.event = None + + DRAW space handlers are called by that space's drawing callback in Blender. + The script is called B{after} the space has been drawn. + + Two of the L{Blender} module variables related to script links assume + different roles for space handlers: + - B{bylink} is the same: True if the script is running as a script link; + - B{link}: integer from the L{Blender}.SpaceHandlers constant dictionary, + tells what space this handler belongs to and the handler's type + (EVENT, DRAW); + - B{event}: + - EVENT handlers: an input event (check keys and mouse events in L{Draw}) + to be processed or ignored. + - DRAW handlers: 0 always. + + B{Guidelines}: + - EVENT handlers can access and change Blender objects just like any other + script, but they should not draw (images, polygons, etc.) to the screen, + use a DRAW handler to do that and if both scripts need to pass information + to each other, use the L{Registry} module. + - DRAW handlers should leave the space in the same state it was before they + executed. OpenGL attributes are automatically saved (pushed) before a DRAW + handler runs and restored (poped) after it finishes, no need to worry about + that. + + Registering scripts: + ==================== + To be registered a script needs two things: - to be either in the default scripts dir or in the user defined scripts path (see User Preferences window -> File Paths tab -> Python path); @@ -163,7 +302,7 @@ Introduction: Documenting scripts: - -------------------- + ==================== The "Scripts Help Browser" script in the Help menu can parse special variables from registered scripts and display help information for users. For that, @@ -236,7 +375,7 @@ Introduction: help browser with the L{Blender.ShowHelp} function. Configuring scripts: - -------------------- + ==================== The L{Blender.Registry<Registry>} module provides a simplified way to keep scripts configuration options in memory and also saved in config files. @@ -328,7 +467,8 @@ Introduction: itself is limited to 60. - B{Scripts Configuration Editor}: + Scripts Configuration Editor: + ----------------------------- This script should be available from the System menu in the Scripts window. It provides a GUI to view and edit saved configuration data, both from the @@ -398,4 +538,5 @@ Introduction: in your script's help info, as done in the ac3d ones. L{Back to Main Page<API_intro>} + =============================== """ diff --git a/source/blender/python/api2_2x/doc/Blender.py b/source/blender/python/api2_2x/doc/Blender.py index b68d9a40d60..f4e02a35459 100644 --- a/source/blender/python/api2_2x/doc/Blender.py +++ b/source/blender/python/api2_2x/doc/Blender.py @@ -10,20 +10,30 @@ """ The main Blender module. -B{New}: L{Run}, L{UpdateMenus}, new options to L{Get}, L{ShowHelp}. +B{New}: L{Run}, L{UpdateMenus}, new options to L{Get}, L{ShowHelp}, +L{SpaceHandlers} dictionary. Blender ======= @type bylink: bool @var bylink: True if the current script is being executed as a script link. -@type link: Blender Object or None -@var link: if this script is a running script link, 'link' points to the - linked Object (can be a scene, object (mesh, camera, lamp), material or - world). If this is not a script link, 'link' is None. -@type event: string -@var event: if this script is a running script link, 'event' tells what - kind of link triggered it (ex: OnLoad, FrameChanged, Redraw, etc.). +@type link: Blender Object or None; integer (space handlers) +@var link: for normal script links, 'link' points to the linked Object (can be + a scene, object (mesh, camera, lamp), material or + world). For space handler script links, 'link' is an integer from the + Blender.L{SpaceHandlers} dictionary. For script not running as script + links, 'link' is None. +@type event: string or int +@var event: this has three possible uses: script link type or events callback + ascii value: + - for normal script links it is a string representing the link type + (OnLoad, FrameChanged, Redraw, etc.). + - for EVENT space handler script links it is the passed event. + - for normal L{GUI<Draw.Register>} scripts I{during the events callback}, + it holds the ascii value of the current event, if it is a valid one. + Users interested in this should also check the builtin 'ord' and 'chr' + Python functions. @type mode: string @var mode: Blender's current mode: - 'interactive': normal mode, with an open window answering to user input; @@ -31,6 +41,10 @@ Blender will exit as soon as it finishes rendering or executing a script (ex: 'C{blender -b <blender file> -P <script>}'). Try 'C{blender -h}' for more detailed informations. +@type SpaceHandlers: constant dictionary +@var SpaceHandlers: dictionary with space handler types. + - VIEW3D_EVENT; + - VIEW3D_DRAW. """ def Set (request, data): diff --git a/source/blender/python/api2_2x/doc/Draw.py b/source/blender/python/api2_2x/doc/Draw.py index a3c42c7cdc2..fab404152c1 100644 --- a/source/blender/python/api2_2x/doc/Draw.py +++ b/source/blender/python/api2_2x/doc/Draw.py @@ -6,7 +6,7 @@ The Blender.Draw submodule. Draw ==== -B{New}: L{PupIntInput}, L{PupFloatInput}, L{PupStrInput}, mouse wheel events. +B{New}: access to ascii values in L{events<Register>} callbacks. This module provides access to a B{windowing interface} in Blender. Its widgets include many kinds of buttons: push, toggle, menu, number, string, slider, @@ -240,6 +240,8 @@ def Register(draw = None, event = None, button = None): is called only once. It's not necessary to re-register the callbacks, they will stay until Draw.Exit is called. It's enough to redraw the screen, when a relevant event is caught. + @note: only during the B{event} callback: the L{Blender}.ascii variable holds + the ascii integer value (if it exists and is valid) of the current event. """ def Redraw(after = 0): diff --git a/source/blender/python/api2_2x/doc/Theme.py b/source/blender/python/api2_2x/doc/Theme.py index facfee068c2..e2e9c74c8ed 100644 --- a/source/blender/python/api2_2x/doc/Theme.py +++ b/source/blender/python/api2_2x/doc/Theme.py @@ -181,8 +181,11 @@ class Theme: @cvar edge_facesel: theme rgba var. @cvar face: theme rgba var. @cvar face_select: theme rgba var. + @cvar face_dot: theme rgba var. @cvar normal: 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 + @cvar facedot_size: size of the face dots on screen in the range [1, 10]. """ diff --git a/source/blender/python/api2_2x/gen_utils.c b/source/blender/python/api2_2x/gen_utils.c index e909de1184c..ba6878b0a5d 100644 --- a/source/blender/python/api2_2x/gen_utils.c +++ b/source/blender/python/api2_2x/gen_utils.c @@ -155,6 +155,10 @@ char *event_to_name( short event ) return "OnSave"; case SCRIPT_REDRAW: return "Redraw"; + case SCRIPT_RENDER: + return "Render"; + case SCRIPT_POSTRENDER: + return "PostRender"; default: return "Unknown"; } @@ -314,6 +318,8 @@ PyObject *EXPP_getScriptLinks( ScriptLink * slink, PyObject * args, event = SCRIPT_FRAMECHANGED; else if( !strcmp( eventname, "Redraw" ) ) event = SCRIPT_REDRAW; + else if( !strcmp( eventname, "Render" ) ) + event = SCRIPT_RENDER; else if( is_scene && !strcmp( eventname, "OnLoad" ) ) event = SCRIPT_ONLOAD; else if( is_scene && !strcmp( eventname, "OnSave" ) ) @@ -465,6 +471,8 @@ PyObject *EXPP_addScriptLink(ScriptLink *slink, PyObject *args, int is_scene) event = SCRIPT_FRAMECHANGED; else if( !strcmp( eventname, "Redraw" ) ) event = SCRIPT_REDRAW; + else if( !strcmp( eventname, "Render" ) ) + event = SCRIPT_RENDER; else if( is_scene && !strcmp( eventname, "OnLoad" ) ) event = SCRIPT_ONLOAD; else if( is_scene && !strcmp( eventname, "OnSave" ) ) diff --git a/source/blender/python/api2_2x/windowTheme.c b/source/blender/python/api2_2x/windowTheme.c index 69ba451f2f5..5f2e06024da 100644 --- a/source/blender/python/api2_2x/windowTheme.c +++ b/source/blender/python/api2_2x/windowTheme.c @@ -39,10 +39,12 @@ #define EXPP_THEME_VTX_SIZE_MIN 1 #define EXPP_THEME_VTX_SIZE_MAX 10 +#define EXPP_THEME_FDOT_SIZE_MIN 1 +#define EXPP_THEME_FDOT_SIZE_MAX 10 #define EXPP_THEME_DRAWTYPE_MIN 1 #define EXPP_THEME_DRAWTYPE_MAX 4 -#define EXPP_THEME_NUMBEROFTHEMES 14 +#define EXPP_THEME_NUMBEROFTHEMES 15 static const EXPP_map_pair themes_map[] = { {"ui", -1}, {"buts", SPACE_BUTS}, @@ -58,6 +60,7 @@ static const EXPP_map_pair themes_map[] = { {"imasel", SPACE_IMASEL}, {"text", SPACE_TEXT}, {"oops", SPACE_OOPS}, + {"time", SPACE_TIME}, {NULL, 0} }; @@ -164,18 +167,21 @@ static PyObject *ThemeSpace_getAttr( BPy_ThemeSpace * self, char *name ) ELSEIF_TSP_RGBA( edge_facesel ) ELSEIF_TSP_RGBA( face ) ELSEIF_TSP_RGBA( face_select ) + ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) 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( "[ssssssssssssssssssssssss]", "theme", + attrib = Py_BuildValue( "[ssssssssssssssssssssssssss]", "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", - "normal", "vertex_size" ); + "face_dot", "normal", "vertex_size", "facedot_size" ); if( attrib != Py_None ) return attrib; @@ -214,6 +220,7 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, ELSEIF_TSP_RGBA( edge_facesel ) ELSEIF_TSP_RGBA( face ) ELSEIF_TSP_RGBA( face_select ) + ELSEIF_TSP_RGBA( face_dot ) ELSEIF_TSP_RGBA( normal ) else if( !strcmp( name, "vertex_size" ) ) { int val; @@ -227,6 +234,19 @@ static int ThemeSpace_setAttr( BPy_ThemeSpace * self, char *name, EXPP_THEME_VTX_SIZE_MIN, EXPP_THEME_VTX_SIZE_MAX ); ret = 0; + } + else if( !strcmp( name, "facedot_size" ) ) { + int val; + + if( !PyInt_Check( value ) ) + return EXPP_ReturnIntError( PyExc_TypeError, + "expected integer value" ); + + val = ( int ) PyInt_AsLong( value ); + tsp->vertex_size = EXPP_ClampInt( val, + EXPP_THEME_FDOT_SIZE_MIN, + EXPP_THEME_FDOT_SIZE_MAX ); + ret = 0; } else return EXPP_ReturnIntError( PyExc_AttributeError, "attribute not found" ); @@ -662,6 +682,9 @@ static PyObject *Theme_get( BPy_Theme * self, PyObject * args ) case SPACE_OOPS: tsp = &btheme->toops; break; + case SPACE_TIME: + tsp = &btheme->ttime; + break; } if( tui ) { diff --git a/source/blender/renderconverter/intern/convertBlenderScene.c b/source/blender/renderconverter/intern/convertBlenderScene.c index 744b568aaac..29782be905c 100644 --- a/source/blender/renderconverter/intern/convertBlenderScene.c +++ b/source/blender/renderconverter/intern/convertBlenderScene.c @@ -2941,7 +2941,7 @@ void RE_rotateBlenderScene(void) R.totvlak=R.totvert=R.totlamp=R.tothalo= 0; do_all_ipos(); - BPY_do_all_scripts(SCRIPT_FRAMECHANGED); + if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED); do_all_keys(); #ifdef __NLA do_all_actions(NULL); diff --git a/source/blender/src/buttons_script.c b/source/blender/src/buttons_script.c index 3088486322f..54cbe328a4e 100644 --- a/source/blender/src/buttons_script.c +++ b/source/blender/src/buttons_script.c @@ -47,6 +47,7 @@ #include "DNA_curve_types.h" #include "DNA_effect_types.h" #include "DNA_group_types.h" +#include "DNA_ID.h" #include "DNA_ika_types.h" #include "DNA_image_types.h" #include "DNA_key_types.h" @@ -59,6 +60,7 @@ #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_sound_types.h" +#include "DNA_text_types.h" #include "DNA_texture_types.h" #include "DNA_userdef_types.h" #include "DNA_vfont_types.h" @@ -77,6 +79,7 @@ #include "BKE_image.h" #include "BKE_ipo.h" #include "BKE_lattice.h" +#include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mesh.h" @@ -87,6 +90,7 @@ #include "BKE_utildefines.h" #include "BLI_blenlib.h" +#include "BLI_dynstr.h" #include "BSE_filesel.h" @@ -111,10 +115,6 @@ /* ************************ function prototypes ********************** */ void draw_scriptlink(uiBlock *, ScriptLink *, int , int , int ) ; - - - - /* *************************** SCRIPT ******************************** */ static void extend_scriptlink(ScriptLink *slink) @@ -141,8 +141,7 @@ static void extend_scriptlink(ScriptLink *slink) slink->flag[slink->totscript]= SCRIPT_FRAMECHANGED; slink->totscript++; - - if(slink->actscript<1) slink->actscript=1; + slink->actscript = slink->totscript; } static void delete_scriptlink(ScriptLink *slink) @@ -172,16 +171,55 @@ static void delete_scriptlink(ScriptLink *slink) } } +static char *scriptlinks_menu_string(void) +{ + char *menu = NULL; + DynStr *ds = BLI_dynstr_new(); + Text *text = G.main->text.first; + int txtcounter = 0; + + if (text) { + BLI_dynstr_append(ds, "Select Script Link%t"); + while (text) { + BLI_dynstr_append(ds, "|"); + BLI_dynstr_append(ds, text->id.name+2); + txtcounter += 1; + text = text->id.next; + } + if (txtcounter) menu = BLI_dynstr_get_cstring(ds); + } + BLI_dynstr_free(ds); + return menu; +} + +static void scriptlinks_pupmenu(ScriptLink *slink) +{ + short menuitem; + char *menustr = scriptlinks_menu_string(); + + if (menustr) { + menuitem = pupmenu_col(menustr, 20); + MEM_freeN(menustr); + if (menuitem > 0) { + Text *text = G.main->text.first; + while (--menuitem) text = text->id.next; + if (text) slink->scripts[slink->totscript - 1]= (ID *)text; + } + } +} + void do_scriptbuts(unsigned short event) { Object *ob=NULL; - ScriptLink *script=NULL; + ScriptLink *slink=NULL; Material *ma; switch (event) { case B_SSCRIPT_ADD: - extend_scriptlink(&G.scene->scriptlink); + slink = &G.scene->scriptlink; + extend_scriptlink(slink); BIF_undo_push("Add scriptlink"); + scriptlinks_pupmenu(slink); break; case B_SSCRIPT_DEL: BIF_undo_push("Delete scriptlink"); @@ -193,31 +231,32 @@ void do_scriptbuts(unsigned short event) ob= OBACT; if (ob && G.buts->scriptblock==ID_OB) { - script= &ob->scriptlink; + slink= &ob->scriptlink; } else if (ob && G.buts->scriptblock==ID_MA) { ma= give_current_material(ob, ob->actcol); - if (ma) script= &ma->scriptlink; + if (ma) slink= &ma->scriptlink; } else if (ob && G.buts->scriptblock==ID_CA) { if (ob->type==OB_CAMERA) - script= &((Camera *)ob->data)->scriptlink; + slink= &((Camera *)ob->data)->scriptlink; } else if (ob && G.buts->scriptblock==ID_LA) { if (ob->type==OB_LAMP) - script= &((Lamp *)ob->data)->scriptlink; + slink= &((Lamp *)ob->data)->scriptlink; } else if (G.buts->scriptblock==ID_WO) { if (G.scene->world) - script= &(G.scene->world->scriptlink); + slink= &(G.scene->world->scriptlink); } if (event==B_SCRIPT_ADD) { - extend_scriptlink(script); + extend_scriptlink(slink); BIF_undo_push("Add scriptlink"); + scriptlinks_pupmenu(slink); } else { - delete_scriptlink(script); + delete_scriptlink(slink); BIF_undo_push("Delete scriptlink"); } break; @@ -235,6 +274,7 @@ void draw_scriptlink(uiBlock *block, ScriptLink *script, int sx, int sy, int sce if (script->totscript) { strcpy(str, "FrameChanged%x 1|"); strcat(str, "Redraw%x 4|"); + strcat(str, "Render%x 16|"); if (scene) { strcat(str, "OnLoad%x 2|"); strcat(str, "OnSave%x 8"); @@ -254,7 +294,7 @@ void draw_scriptlink(uiBlock *block, ScriptLink *script, int sx, int sy, int sce if (script->totscript) uiDefBut(block, BUT, B_SSCRIPT_DEL, "Del", (short)(sx+200), (short)sy-20, 40, 19, 0, 0, 0, 0, 0, "Delete the current Script link"); - uiDefBut(block, LABEL, 0, "Scene scriptlink", sx,sy-20,140,20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Scene Script link", sx,sy-20,140,20, 0, 0, 0, 0, 0, ""); } else { @@ -263,7 +303,7 @@ void draw_scriptlink(uiBlock *block, ScriptLink *script, int sx, int sy, int sce if (script->totscript) uiDefBut(block, BUT, B_SCRIPT_DEL, "Del", (short)(sx+200), (short)sy-20, 40, 19, 0, 0, 0, 0, 0, "Delete the current Script link"); - uiDefBut(block, LABEL, 0, "Selected scriptlink", sx,sy-20,140,20, 0, 0, 0, 0, 0, ""); + uiDefBut(block, LABEL, 0, "Selected Script link", sx,sy-20,140,20, 0, 0, 0, 0, 0, ""); } } @@ -276,53 +316,58 @@ static void script_panel_scriptlink(void) ScriptLink *script=NULL; Material *ma; int xco = 10; - + block= uiNewBlock(&curarea->uiblocks, "script_panel_scriptlink", UI_EMBOSS, UI_HELV, curarea->win); if(uiNewPanel(curarea, block, "Scriptlinks", "Script", 0, 0, 318, 204)==0) return; - - - ob= OBACT; - if(ob) - uiDefIconButS(block, ROW, B_REDR, ICON_OBJECT, xco,180,25,20, &G.buts->scriptblock, 2.0, (float)ID_OB, 0, 0, "Displays Object script links"); - if(ob && give_current_material(ob, ob->actcol)) - uiDefIconButS(block, ROW, B_REDR, ICON_MATERIAL, xco+=25,180,25,20, &G.buts->scriptblock, 2.0, (float)ID_MA, 0, 0, "Displays Material script links "); + uiDefButI(block, TOG|BIT|13, REDRAWBUTSSCRIPT, + "Enable Script Links", xco, 200, 150, 20, &G.f, 0, 0, 0, 0, + "Enable execution of all assigned Script links"); + /* for proper alignment: */ + uiDefBut(block, LABEL, 0, "", 160, 200,150,20, NULL, 0.0, 0.0, 0, 0, ""); + + if (G.f & G_DOSCRIPTLINKS) { + ob= OBACT; + if(ob) + uiDefIconButS(block, ROW, B_REDR, ICON_OBJECT, xco,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_OB, 0, 0, "Displays Object script links"); + + if(ob && give_current_material(ob, ob->actcol)) + uiDefIconButS(block, ROW, B_REDR, ICON_MATERIAL, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_MA, 0, 0, "Displays Material script links "); - if(G.scene->world) - uiDefIconButS(block, ROW, B_REDR, ICON_WORLD, xco+=25,180,25,20, &G.buts->scriptblock, 2.0, (float)ID_WO, 0, 0, "Displays World script links"); + if(G.scene->world) + uiDefIconButS(block, ROW, B_REDR, ICON_WORLD, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_WO, 0, 0, "Displays World script links"); - if(ob && ob->type==OB_CAMERA) - uiDefIconButS(block, ROW, B_REDR, ICON_CAMERA, xco+=25,180,25,20, &G.buts->scriptblock, 2.0, (float)ID_CA, 0, 0, "Displays Camera script links"); + if(ob && ob->type==OB_CAMERA) + uiDefIconButS(block, ROW, B_REDR, ICON_CAMERA, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_CA, 0, 0, "Displays Camera script links"); - if(ob && ob->type==OB_LAMP) - uiDefIconButS(block, ROW, B_REDR, ICON_LAMP, xco+=25,180,25,20, &G.buts->scriptblock, 2.0, (float)ID_LA, 0, 0, "Displays Lamp script links"); + if(ob && ob->type==OB_LAMP) + uiDefIconButS(block, ROW, B_REDR, ICON_LAMP, xco+=25,175,25,20, &G.buts->scriptblock, 2.0, (float)ID_LA, 0, 0, "Displays Lamp script links"); - if (ob && G.buts->scriptblock==ID_OB) { - script= &ob->scriptlink; + if (ob && G.buts->scriptblock==ID_OB) { + script= &ob->scriptlink; - } else if (ob && G.buts->scriptblock==ID_MA) { - ma= give_current_material(ob, ob->actcol); - if (ma) script= &ma->scriptlink; + } else if (ob && G.buts->scriptblock==ID_MA) { + ma= give_current_material(ob, ob->actcol); + if (ma) script= &ma->scriptlink; - } else if (ob && G.buts->scriptblock==ID_CA) { - if (ob->type==OB_CAMERA) - script= &((Camera *)ob->data)->scriptlink; + } else if (ob && G.buts->scriptblock==ID_CA) { + if (ob->type==OB_CAMERA) + script= &((Camera *)ob->data)->scriptlink; - } else if (ob && G.buts->scriptblock==ID_LA) { - if (ob->type==OB_LAMP) - script= &((Lamp *)ob->data)->scriptlink; - - } else if (G.buts->scriptblock==ID_WO) { - if (G.scene->world) - script= &(G.scene->world->scriptlink); - } - - if (script) draw_scriptlink(block, script, 10, 140, 0); + } else if (ob && G.buts->scriptblock==ID_LA) { + if (ob->type==OB_LAMP) + script= &((Lamp *)ob->data)->scriptlink; - draw_scriptlink(block, &G.scene->scriptlink, 10, 80, 1); + } else if (G.buts->scriptblock==ID_WO) { + if (G.scene->world) + script= &(G.scene->world->scriptlink); + } + if (script) draw_scriptlink(block, script, 10, 140, 0); + draw_scriptlink(block, &G.scene->scriptlink, 10, 80, 1); + } } diff --git a/source/blender/src/drawscript.c b/source/blender/src/drawscript.c index 2c52c20ee95..c4ec1a4db3a 100644 --- a/source/blender/src/drawscript.c +++ b/source/blender/src/drawscript.c @@ -112,11 +112,12 @@ void winqreadscriptspace(struct ScrArea *sa, void *spacedata, struct BWinEvent * { unsigned short event = evt->event; short val = evt->val; + char ascii = evt->ascii; SpaceScript *sc = curarea->spacedata.first; Script *script = sc->script; if (script) { - BPY_spacescript_do_pywin_event(sc, event, val); + BPY_spacescript_do_pywin_event(sc, event, val, ascii); if (!script->flags) {/* finished with this script, let's free it */ if (script->lastspace != SPACE_SCRIPT) diff --git a/source/blender/src/drawview.c b/source/blender/src/drawview.c index dadb1c2acf5..9b96db9309b 100644 --- a/source/blender/src/drawview.c +++ b/source/blender/src/drawview.c @@ -2030,9 +2030,13 @@ void drawview3dspace(ScrArea *sa, void *spacedata) } } + /* run any view3d draw handler script links */ + if (sa->scriptlink.totscript) + BPY_do_spacehandlers(sa, 0, SPACEHANDLER_VIEW3D_DRAW); - /* scene redraw script link */ - if(G.scene->scriptlink.totscript && !during_script()) { + /* run scene redraw script links */ + if((G.f & G_DOSCRIPTLINKS) && G.scene->scriptlink.totscript && + !during_script()) { BPY_do_pyscript((ID *)G.scene, SCRIPT_REDRAW); } @@ -2084,7 +2088,7 @@ void drawview3d_render(struct View3D *v3d) clear_all_constraints(); do_all_ipos(); - BPY_do_all_scripts(SCRIPT_FRAMECHANGED); + if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED); do_all_keys(); do_all_actions(NULL); do_all_ikas(); diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c index 82c842ec737..39a5f09eaff 100644 --- a/source/blender/src/header_view3d.c +++ b/source/blender/src/header_view3d.c @@ -55,6 +55,7 @@ #include "DNA_space_types.h" #include "DNA_view3d_types.h" #include "DNA_image_types.h" +#include "DNA_text_types.h" /* for space handlers */ #include "DNA_texture_types.h" #include "BKE_library.h" @@ -335,6 +336,94 @@ static uiBlock *view3d_view_alignviewmenu(void *arg_unused) return block; } +static void do_view3d_view_spacehandlers(void *arg, int event) +{ + Text *text = G.main->text.first; + unsigned short menu_evt_num = 0; + + if (event > 0) { + while (text) { + if (++menu_evt_num == event) { + + if (BPY_has_spacehandler(text, curarea)) + BPY_del_spacehandler(text, curarea); + else + BPY_add_spacehandler(text, curarea, SPACE_VIEW3D); + + break; + } + text = text->id.next; + } + } + + allqueue(REDRAWVIEW3D, 1); +} + +static uiBlock *view3d_view_spacehandlers(void *arg_unused) +{ + uiBlock *block; + short yco= 0, menuwidth=120; + Text *text = G.main->text.first; + ScrArea *sa = curarea; + unsigned short handlertype; + int icontype, slinks_num = 0; + unsigned short menu_evt_num = 0; + char menustr[64]; + static char msg_tog_on[] = "Click to enable"; + static char msg_tog_off[]= "Click to disable"; + char *tip = NULL; + + block= uiNewBlock(&curarea->uiblocks, "view3d_view_spacehandlers", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin); + uiBlockSetButmFunc(block, do_view3d_view_spacehandlers, NULL); + + while (text) { + menu_evt_num++; + handlertype = BPY_is_spacehandler(text, SPACE_VIEW3D); + + if (handlertype) { + slinks_num++; + + /* mark text as script, so we can remove its link if its header + * becomes corrupt and it's not recognized anymore */ + if (!(text->flags & TXT_ISSCRIPT)) text->flags |= TXT_ISSCRIPT; + + if (handlertype == SPACEHANDLER_VIEW3D_EVENT) + BLI_strncpy(menustr, "Event: ", 8); + else + BLI_strncpy(menustr, "Draw: ", 8); + BLI_strncpy(menustr+7, text->id.name+2, 22); + + if (BPY_has_spacehandler(text, sa)) { + icontype = ICON_CHECKBOX_HLT; + tip = msg_tog_off; + } + else { + icontype = ICON_CHECKBOX_DEHLT; + tip = msg_tog_on; + } + + uiDefIconTextBut(block, BUTM, 1, icontype, menustr, 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, menu_evt_num, tip); + } + else if (text->flags & TXT_ISSCRIPT) { + /* if bit set, text was a space handler, but its header got corrupted, + * so we need to remove the link here */ + BPY_del_spacehandler(text, sa); + text->flags &=~TXT_ISSCRIPT; + } + + text = text->id.next; + } + + if (slinks_num == 0) { + uiDefIconTextBut(block, BUTM, 1, ICON_SCRIPT, "None Available", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, -1, "None of the texts in the Text Editor is a 3D View space handler"); + } + + uiBlockSetDirection(block, UI_RIGHT); + uiTextBoundsBlock(block, 50); + + return block; +} + static void do_view3d_viewmenu(void *arg, int event) { extern int play_anim(int mode); @@ -444,6 +533,9 @@ static uiBlock *view3d_viewmenu(void *arg_unused) uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Play Back Animation|Alt A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 13, ""); + uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, ""); + uiDefIconTextBlockBut(block, view3d_view_spacehandlers, NULL, ICON_RIGHTARROW_THIN, "Space Handler Scripts", 0, yco-=20, 120, 19, ""); + if(curarea->headertype==HEADERTOP) { uiBlockSetDirection(block, UI_DOWN); } diff --git a/source/blender/src/headerbuttons.c b/source/blender/src/headerbuttons.c index c800f9c24ef..b66d7991549 100644 --- a/source/blender/src/headerbuttons.c +++ b/source/blender/src/headerbuttons.c @@ -507,7 +507,7 @@ static void do_update_for_newframe(int mute) /* layers/materials, object ipos are calculted in where_is_object (too) */ do_all_ipos(); - BPY_do_all_scripts(SCRIPT_FRAMECHANGED); + if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_FRAMECHANGED); clear_all_constraints(); do_all_keys(); diff --git a/source/blender/src/renderwin.c b/source/blender/src/renderwin.c index ffa917530b0..6d5ab76657f 100644 --- a/source/blender/src/renderwin.c +++ b/source/blender/src/renderwin.c @@ -80,6 +80,7 @@ #include "BIF_toets.h" #include "BDR_editobject.h" +#include "BPY_extern.h" /* for BPY_do_all_scripts */ #include "BSE_view.h" #include "BSE_drawview.h" @@ -1143,6 +1144,16 @@ void BIF_renderwin_make_active(void) /* set up display, render an image or scene */ void BIF_do_render(int anim) { + int slink_flag = 0; + + if (G.f & G_DOSCRIPTLINKS) { + BPY_do_all_scripts(SCRIPT_RENDER); + if (!anim) { /* avoid FRAMECHANGED slink in render callback */ + G.f &= ~G_DOSCRIPTLINKS; + slink_flag = 1; + } + } + /* if start render in 3d win, use layer from window (e.g also local view) */ if(curarea && curarea->spacetype==SPACE_VIEW3D) { int lay= G.scene->lay; @@ -1155,6 +1166,9 @@ void BIF_do_render(int anim) G.scene->lay= lay; } else do_render(NULL, anim, 0); + + if (slink_flag) G.f |= G_DOSCRIPTLINKS; + if (G.f & G_DOSCRIPTLINKS) BPY_do_all_scripts(SCRIPT_POSTRENDER); } /* set up display, render the current area view in an image */ diff --git a/source/blender/src/space.c b/source/blender/src/space.c index 30dc39c6a2e..f613cb6a055 100644 --- a/source/blender/src/space.c +++ b/source/blender/src/space.c @@ -732,7 +732,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) if(event==UI_BUT_EVENT) do_butspace(val); // temporal, view3d deserves own queue? - /* we consider manupilator a button, defaulting to leftmouse */ + /* we consider manipulator a button, defaulting to leftmouse */ if(event==LEFTMOUSE) if(BIF_do_manipulator(sa)) return; /* swap mouse buttons based on user preference */ @@ -740,7 +740,12 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt) if (event==LEFTMOUSE) event = RIGHTMOUSE; else if (event==RIGHTMOUSE) event = LEFTMOUSE; } - + + /* run any view3d event handler script links */ + if (event && sa->scriptlink.totscript) + if (BPY_do_spacehandlers(sa, event, SPACEHANDLER_VIEW3D_EVENT)) + return; /* return if event was processed (swallowed) by handler(s) */ + /* TEXTEDITING?? */ if((G.obedit) && G.obedit->type==OB_FONT) { switch(event) { diff --git a/source/blender/src/usiblender.c b/source/blender/src/usiblender.c index 241dc8cd45f..895bd90f840 100644 --- a/source/blender/src/usiblender.c +++ b/source/blender/src/usiblender.c @@ -460,10 +460,8 @@ void BIF_write_file(char *target) if (BLI_streq(target, "")) return; - /*Send the OnSave event*/ - if (G.f & G_SCENESCRIPT) { - BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE); - } + /* send the OnSave event */ + if (G.f & G_DOSCRIPTLINKS) BPY_do_pyscript(&G.scene->id, SCRIPT_ONSAVE); for (li= G.main->library.first; li; li= li->id.next) { if (BLI_streq(li->name, target)) { diff --git a/source/creator/creator.c b/source/creator/creator.c index 62d638d167b..1c8cab55cb5 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -188,7 +188,7 @@ static void print_help(void) printf (" -d\t\tTurn debugging on\n"); printf (" -noaudio\tDisable audio on systems that support audio\n"); printf (" -h\t\tPrint this help text\n"); - printf (" -y\t\tDisable OnLoad scene scripts, use -Y to find out why its -y\n"); + printf (" -y\t\tDisable script links, use -Y to find out why its -y\n"); printf (" -P <filename>\tRun the given Python script (filename or Blender Text)\n"); #ifdef WIN32 printf (" -R\t\tRegister .blend extension\n"); @@ -276,7 +276,7 @@ int main(int argc, char **argv) /* first test for background */ - G.f |= G_SCENESCRIPT; /* scenescript always set! */ + G.f |= G_DOSCRIPTLINKS; /* script links enabled by default */ for(a=1; a<argc; a++) { @@ -306,11 +306,11 @@ int main(int argc, char **argv) break; case 'y': - G.f &= ~G_SCENESCRIPT; + G.f &= ~G_DOSCRIPTLINKS; break; case 'Y': - printf ("-y was used to disable scene scripts because,\n"); + printf ("-y was used to disable script links because,\n"); printf ("\t-p being taken, Ton was of the opinion that Y\n"); printf ("\tlooked like a split (disabled) snake, and also\n"); printf ("\twas similar to a python's tongue (unproven).\n\n"); |