From 09fb5d6b8d1aafc66d33bded48b149105be41675 Mon Sep 17 00:00:00 2001 From: Willian Padovani Germano Date: Sun, 8 May 2005 21:20:34 +0000 Subject: [PATCH] BPython: - Made Blender.event var (previously only used by script links) hold ascii value -- where it applies -- of current event during events callback registered with Draw.Register(gui, events, button_events). Useful for gui scripts like Campbell's Python console. No problem using this var to hold the value, since in gui scripts it was not used (always None). - Updated Window and Window.Theme with new theme vars and the Time space. - Script links: -- Added "Render" event for script links (runs twice, second time as "PostEvent", for clean-up actions). Now FrameChanged links don't run when a single pic is rendered. -- Added "Enable Script Links" button in the script buttons tab. Now this bit gets saved in .blends along with the rest of G.f, so users can define per .blend if they are on or off by default. "blender -y" also disables all slinks as happened before with OnLoad ones only. -- Other small changes in the script buttons tab: When a link is added (button "new"), it becomes the active one for the window, no need to press a button to reach it. Also, a pupmenu showing all available texts is shown when "new" is pressed, so users can choose a text w/o having to type. Cancel the popup to leave the string button empty (link exists, but has no script assigned). A pulldown would be better UI-wise, but it's kinda weird to show both scripts and normal texts (Blender doesn't differentiate them) in a script links pulldown. With a popup we can show only texts ending in ".py" (not done in this commit, need opinions) and if the script has no or another extension, case of many in old and current .blend's, there's still the string box for writing its name. -- Implemented Ton's space handler script links: Right now only for the 3d View, but it's trivial to add for others. There are two types: EVENT, to receive 3d View events from a chosen window and DRAW, to draw on the window. Ton's idea was to give scripts a controlled way to integrate better within Blender. Here's how it works: - scripts must have a proper header, like: # SPACEHANDLER.VIEW3D.EVENT and then they are shown in 3d View's View menu, "Space Handler Scripts" submenu. Check (mark, click on it) a script to make it active. EVENT handlers should consult the Blender.event var to get the current event, which can be compared with values from the Draw module: import Blender from Blender import Draw evt = Blender.event if evt == Draw.AKEY: print "a" elif evt == Draw.LEFTMOUSE: print "left mouse button" else: return # ignore, pass event back to Blender Blender.event = None # tell Blender not to process itself the event DRAW handlers are free to draw to their owner 3D View. OpenGL attributes and modelview and projection matrices are pushed before running the handler and poped when it finishes. To communicate between EVENT and DRAW handler scripts we have the Blender.Registry module, as always. Still need to code some nice example, which should also serve to test properly space handlers. Simple tests went fine. - doc updates about the additions. ======= Note: the UI part of the space handlers and script links is of course open for changes, I just tried to make it understandable. Probably we won't use the scriptlinks icon for "None Available" (check 3d View -> View -> Space Handler Scripts), though it hints at what space handlers are. The tooltips may not be accepted either, since other menus don't use them. Opinions welcomed. --- .../blender/blenkernel/BKE_bad_level_calls.h | 3 + source/blender/blenkernel/BKE_global.h | 2 +- .../blenkernel/bad_level_call_stubs/stubs.c | 1 + source/blender/blenkernel/intern/blender.c | 9 +- source/blender/blenkernel/intern/object.c | 2 +- source/blender/blenkernel/intern/scene.c | 4 +- source/blender/blenkernel/intern/screen.c | 3 +- source/blender/blenkernel/intern/text.c | 3 +- source/blender/blenloader/intern/readfile.c | 7 +- source/blender/blenloader/intern/writefile.c | 3 + source/blender/makesdna/DNA_screen_types.h | 2 + .../blender/makesdna/DNA_scriptlink_types.h | 16 +- source/blender/makesdna/DNA_text_types.h | 4 +- source/blender/python/BPY_extern.h | 47 +-- source/blender/python/BPY_interface.c | 273 +++++++++++++++++- source/blender/python/api2_2x/Blender.c | 14 +- source/blender/python/api2_2x/Draw.c | 22 +- source/blender/python/api2_2x/Draw.h | 2 +- source/blender/python/api2_2x/Window.c | 1 + .../blender/python/api2_2x/doc/API_intro.py | 11 +- .../blender/python/api2_2x/doc/API_related.py | 157 +++++++++- source/blender/python/api2_2x/doc/Blender.py | 30 +- source/blender/python/api2_2x/doc/Draw.py | 4 +- source/blender/python/api2_2x/doc/Theme.py | 3 + source/blender/python/api2_2x/gen_utils.c | 8 + source/blender/python/api2_2x/windowTheme.c | 29 +- .../intern/convertBlenderScene.c | 2 +- source/blender/src/buttons_script.c | 147 ++++++---- source/blender/src/drawscript.c | 3 +- source/blender/src/drawview.c | 10 +- source/blender/src/header_view3d.c | 92 ++++++ source/blender/src/headerbuttons.c | 2 +- source/blender/src/renderwin.c | 14 + source/blender/src/space.c | 9 +- source/blender/src/usiblender.c | 6 +- source/creator/creator.c | 8 +- 36 files changed, 821 insertions(+), 132 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 #include /* for BLI_last_slash() */ +#include "BIF_gl.h" /* glPushAttrib, glPopAttrib for DRAW space handlers */ #include /* for pupmenu() */ #include #include @@ -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 #include /* for SPACE_VIEW3D */ #include /* for SPACE_VIEW3D */ +#include #include #include #include @@ -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}: + - L{Special features}: - 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}). + + 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} 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} + =============================== """ 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} 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 -P