Blender V2.61 - r43446

screen_edit.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2008 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include <string.h>
00031 #include <math.h>
00032 
00033 
00034 #include "MEM_guardedalloc.h"
00035 
00036 #include "DNA_scene_types.h"
00037 #include "DNA_userdef_types.h"
00038 
00039 #include "BLI_blenlib.h"
00040 #include "BLI_utildefines.h"
00041 
00042 #include "BKE_context.h"
00043 #include "BKE_global.h"
00044 #include "BKE_library.h"
00045 #include "BKE_main.h"
00046 #include "BKE_node.h"
00047 #include "BKE_screen.h"
00048 #include "BKE_scene.h"
00049 
00050 #include "BIF_gl.h"
00051 #include "BIF_glutil.h"
00052 
00053 #include "WM_api.h"
00054 #include "WM_types.h"
00055 
00056 #include "ED_image.h"
00057 #include "ED_object.h"
00058 #include "ED_screen.h"
00059 #include "ED_screen_types.h"
00060 #include "ED_fileselect.h"
00061 #include "ED_clip.h"
00062 #include "ED_render.h"
00063 
00064 #include "UI_interface.h"
00065 
00066 /* XXX actually should be not here... solve later */
00067 #include "wm_subwindow.h"
00068 
00069 #include "screen_intern.h"  /* own module include */
00070 
00071 
00072 /* ******************* screen vert, edge, area managing *********************** */
00073 
00074 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
00075 {
00076     ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
00077     sv->vec.x= x;
00078     sv->vec.y= y;
00079     
00080     BLI_addtail(&sc->vertbase, sv);
00081     return sv;
00082 }
00083 
00084 static void sortscrvert(ScrVert **v1, ScrVert **v2)
00085 {
00086     ScrVert *tmp;
00087     
00088     if (*v1 > *v2) {
00089         tmp= *v1;
00090         *v1= *v2;
00091         *v2= tmp;   
00092     }
00093 }
00094 
00095 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
00096 {
00097     ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
00098     
00099     sortscrvert(&v1, &v2);
00100     se->v1= v1;
00101     se->v2= v2;
00102     
00103     BLI_addtail(&sc->edgebase, se);
00104     return se;
00105 }
00106 
00107 
00108 ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
00109 {
00110     ScrEdge *se;
00111     
00112     sortscrvert(&v1, &v2);
00113     for (se= sc->edgebase.first; se; se= se->next)
00114         if(se->v1==v1 && se->v2==v2)
00115             return se;
00116     
00117     return NULL;
00118 }
00119 
00120 void removedouble_scrverts(bScreen *sc)
00121 {
00122     ScrVert *v1, *verg;
00123     ScrEdge *se;
00124     ScrArea *sa;
00125     
00126     verg= sc->vertbase.first;
00127     while(verg) {
00128         if(verg->newv==NULL) {  /* !!! */
00129             v1= verg->next;
00130             while(v1) {
00131                 if(v1->newv==NULL) {    /* !?! */
00132                     if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
00133                         /* printf("doublevert\n"); */
00134                         v1->newv= verg;
00135                     }
00136                 }
00137                 v1= v1->next;
00138             }
00139         }
00140         verg= verg->next;
00141     }
00142 
00143     /* replace pointers in edges and faces */
00144     se= sc->edgebase.first;
00145     while(se) {
00146         if(se->v1->newv) se->v1= se->v1->newv;
00147         if(se->v2->newv) se->v2= se->v2->newv;
00148         /* edges changed: so.... */
00149         sortscrvert(&(se->v1), &(se->v2));
00150         se= se->next;
00151     }
00152     sa= sc->areabase.first;
00153     while(sa) {
00154         if(sa->v1->newv) sa->v1= sa->v1->newv;
00155         if(sa->v2->newv) sa->v2= sa->v2->newv;
00156         if(sa->v3->newv) sa->v3= sa->v3->newv;
00157         if(sa->v4->newv) sa->v4= sa->v4->newv;
00158         sa= sa->next;
00159     }
00160 
00161     /* remove */
00162     verg= sc->vertbase.first;
00163     while(verg) {
00164         v1= verg->next;
00165         if(verg->newv) {
00166             BLI_remlink(&sc->vertbase, verg);
00167             MEM_freeN(verg);
00168         }
00169         verg= v1;
00170     }
00171 
00172 }
00173 
00174 void removenotused_scrverts(bScreen *sc)
00175 {
00176     ScrVert *sv, *svn;
00177     ScrEdge *se;
00178     
00179     /* we assume edges are ok */
00180     
00181     se= sc->edgebase.first;
00182     while(se) {
00183         se->v1->flag= 1;
00184         se->v2->flag= 1;
00185         se= se->next;
00186     }
00187     
00188     sv= sc->vertbase.first;
00189     while(sv) {
00190         svn= sv->next;
00191         if(sv->flag==0) {
00192             BLI_remlink(&sc->vertbase, sv);
00193             MEM_freeN(sv);
00194         }
00195         else sv->flag= 0;
00196         sv= svn;
00197     }
00198 }
00199 
00200 void removedouble_scredges(bScreen *sc)
00201 {
00202     ScrEdge *verg, *se, *sn;
00203     
00204     /* compare */
00205     verg= sc->edgebase.first;
00206     while(verg) {
00207         se= verg->next;
00208         while(se) {
00209             sn= se->next;
00210             if(verg->v1==se->v1 && verg->v2==se->v2) {
00211                 BLI_remlink(&sc->edgebase, se);
00212                 MEM_freeN(se);
00213             }
00214             se= sn;
00215         }
00216         verg= verg->next;
00217     }
00218 }
00219 
00220 void removenotused_scredges(bScreen *sc)
00221 {
00222     ScrEdge *se, *sen;
00223     ScrArea *sa;
00224     int a=0;
00225     
00226     /* sets flags when edge is used in area */
00227     sa= sc->areabase.first;
00228     while(sa) {
00229         se= screen_findedge(sc, sa->v1, sa->v2);
00230         if(se==NULL) printf("error: area %d edge 1 doesn't exist\n", a);
00231         else se->flag= 1;
00232         se= screen_findedge(sc, sa->v2, sa->v3);
00233         if(se==NULL) printf("error: area %d edge 2 doesn't exist\n", a);
00234         else se->flag= 1;
00235         se= screen_findedge(sc, sa->v3, sa->v4);
00236         if(se==NULL) printf("error: area %d edge 3 doesn't exist\n", a);
00237         else se->flag= 1;
00238         se= screen_findedge(sc, sa->v4, sa->v1);
00239         if(se==NULL) printf("error: area %d edge 4 doesn't exist\n", a);
00240         else se->flag= 1;
00241         sa= sa->next;
00242         a++;
00243     }
00244     se= sc->edgebase.first;
00245     while(se) {
00246         sen= se->next;
00247         if(se->flag==0) {
00248             BLI_remlink(&sc->edgebase, se);
00249             MEM_freeN(se);
00250         }
00251         else se->flag= 0;
00252         se= sen;
00253     }
00254 }
00255 
00256 int scredge_is_horizontal(ScrEdge *se)
00257 {
00258     return (se->v1->vec.y == se->v2->vec.y);
00259 }
00260 
00261 ScrEdge *screen_find_active_scredge(bScreen *sc, int mx, int my)
00262 {
00263     ScrEdge *se;
00264     
00265     for (se= sc->edgebase.first; se; se= se->next) {
00266         if (scredge_is_horizontal(se)) {
00267             short min, max;
00268             min= MIN2(se->v1->vec.x, se->v2->vec.x);
00269             max= MAX2(se->v1->vec.x, se->v2->vec.x);
00270             
00271             if (abs(my-se->v1->vec.y)<=2 && mx>=min && mx<=max)
00272                 return se;
00273         } 
00274         else {
00275             short min, max;
00276             min= MIN2(se->v1->vec.y, se->v2->vec.y);
00277             max= MAX2(se->v1->vec.y, se->v2->vec.y);
00278             
00279             if (abs(mx-se->v1->vec.x)<=2 && my>=min && my<=max)
00280                 return se;
00281         }
00282     }
00283     
00284     return NULL;
00285 }
00286 
00287 
00288 
00289 /* adds no space data */
00290 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
00291 {
00292     ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
00293     sa->v1= v1;
00294     sa->v2= v2;
00295     sa->v3= v3;
00296     sa->v4= v4;
00297     sa->headertype= headertype;
00298     sa->spacetype= sa->butspacetype= spacetype;
00299     
00300     BLI_addtail(&sc->areabase, sa);
00301     
00302     return sa;
00303 }
00304 
00305 static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
00306 {
00307     
00308     ED_area_exit(C, sa);
00309     
00310     BKE_screen_area_free(sa);
00311     
00312     BLI_remlink(&sc->areabase, sa);
00313     MEM_freeN(sa);
00314 }
00315 
00316 /* return 0: no split possible */
00317 /* else return (integer) screencoordinate split point */
00318 static short testsplitpoint(ScrArea *sa, char dir, float fac)
00319 {
00320     short x, y;
00321     
00322     // area big enough?
00323     if(dir=='v' && (sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX)) return 0;
00324     if(dir=='h' && (sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY)) return 0;
00325     
00326     // to be sure
00327     CLAMP(fac, 0.0f, 1.0f);
00328     
00329     if(dir=='h') {
00330         y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
00331         
00332         if(y- sa->v1->vec.y < AREAMINY) 
00333             y= sa->v1->vec.y+ AREAMINY;
00334         else if(sa->v2->vec.y- y < AREAMINY) 
00335             y= sa->v2->vec.y- AREAMINY;
00336         else y-= (y % AREAGRID);
00337         
00338         return y;
00339     }
00340     else {
00341         x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
00342         
00343         if(x- sa->v1->vec.x < AREAMINX) 
00344             x= sa->v1->vec.x+ AREAMINX;
00345         else if(sa->v4->vec.x- x < AREAMINX) 
00346             x= sa->v4->vec.x- AREAMINX;
00347         else x-= (x % AREAGRID);
00348         
00349         return x;
00350     }
00351 }
00352 
00353 ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
00354 {
00355     ScrArea *newa=NULL;
00356     ScrVert *sv1, *sv2;
00357     short split;
00358     
00359     if(sa==NULL) return NULL;
00360     
00361     split= testsplitpoint(sa, dir, fac);
00362     if(split==0) return NULL;
00363     
00364     if(dir=='h') {
00365         /* new vertices */
00366         sv1= screen_addvert(sc, sa->v1->vec.x, split);
00367         sv2= screen_addvert(sc, sa->v4->vec.x, split);
00368         
00369         /* new edges */
00370         screen_addedge(sc, sa->v1, sv1);
00371         screen_addedge(sc, sv1, sa->v2);
00372         screen_addedge(sc, sa->v3, sv2);
00373         screen_addedge(sc, sv2, sa->v4);
00374         screen_addedge(sc, sv1, sv2);
00375         
00376         /* new areas: top */
00377         newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
00378         area_copy_data(newa, sa, 0);
00379         
00380         /* area below */
00381         sa->v2= sv1;
00382         sa->v3= sv2;
00383         
00384     }
00385     else {
00386         /* new vertices */
00387         sv1= screen_addvert(sc, split, sa->v1->vec.y);
00388         sv2= screen_addvert(sc, split, sa->v2->vec.y);
00389         
00390         /* new edges */
00391         screen_addedge(sc, sa->v1, sv1);
00392         screen_addedge(sc, sv1, sa->v4);
00393         screen_addedge(sc, sa->v2, sv2);
00394         screen_addedge(sc, sv2, sa->v3);
00395         screen_addedge(sc, sv1, sv2);
00396         
00397         /* new areas: left */
00398         newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
00399         area_copy_data(newa, sa, 0);
00400         
00401         /* area right */
00402         sa->v1= sv1;
00403         sa->v2= sv2;
00404     }
00405     
00406     /* remove double vertices en edges */
00407     if(merge)
00408         removedouble_scrverts(sc);
00409     removedouble_scredges(sc);
00410     removenotused_scredges(sc);
00411     
00412     return newa;
00413 }
00414 
00415 /* empty screen, with 1 dummy area without spacedata */
00416 /* uses window size */
00417 bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name)
00418 {
00419     bScreen *sc;
00420     ScrVert *sv1, *sv2, *sv3, *sv4;
00421     
00422     sc= alloc_libblock(&G.main->screen, ID_SCR, name);
00423     sc->scene= scene;
00424     sc->do_refresh= 1;
00425     sc->redraws_flag= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
00426     sc->winid= win->winid;
00427     
00428     sv1= screen_addvert(sc, 0, 0);
00429     sv2= screen_addvert(sc, 0, win->sizey-1);
00430     sv3= screen_addvert(sc, win->sizex-1, win->sizey-1);
00431     sv4= screen_addvert(sc, win->sizex-1, 0);
00432     
00433     screen_addedge(sc, sv1, sv2);
00434     screen_addedge(sc, sv2, sv3);
00435     screen_addedge(sc, sv3, sv4);
00436     screen_addedge(sc, sv4, sv1);
00437     
00438     /* dummy type, no spacedata */
00439     screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY);
00440         
00441     return sc;
00442 }
00443 
00444 static void screen_copy(bScreen *to, bScreen *from)
00445 {
00446     ScrVert *s1, *s2;
00447     ScrEdge *se;
00448     ScrArea *sa, *saf;
00449     
00450     /* free contents of 'to', is from blenkernel screen.c */
00451     free_screen(to);
00452     
00453     BLI_duplicatelist(&to->vertbase, &from->vertbase);
00454     BLI_duplicatelist(&to->edgebase, &from->edgebase);
00455     BLI_duplicatelist(&to->areabase, &from->areabase);
00456     to->regionbase.first= to->regionbase.last= NULL;
00457     
00458     s2= to->vertbase.first;
00459     for(s1= from->vertbase.first; s1; s1= s1->next, s2= s2->next) {
00460         s1->newv= s2;
00461     }
00462     
00463     for(se= to->edgebase.first; se; se= se->next) {
00464         se->v1= se->v1->newv;
00465         se->v2= se->v2->newv;
00466         sortscrvert(&(se->v1), &(se->v2));
00467     }
00468     
00469     saf= from->areabase.first;
00470     for(sa= to->areabase.first; sa; sa= sa->next, saf= saf->next) {
00471         sa->v1= sa->v1->newv;
00472         sa->v2= sa->v2->newv;
00473         sa->v3= sa->v3->newv;
00474         sa->v4= sa->v4->newv;
00475         
00476         sa->spacedata.first= sa->spacedata.last= NULL;
00477         sa->regionbase.first= sa->regionbase.last= NULL;
00478         sa->actionzones.first= sa->actionzones.last= NULL;
00479         sa->handlers.first= sa->handlers.last= NULL;
00480         
00481         area_copy_data(sa, saf, 0);
00482     }
00483     
00484     /* put at zero (needed?) */
00485     for(s1= from->vertbase.first; s1; s1= s1->next)
00486         s1->newv= NULL;
00487 
00488 }
00489 
00490 
00491 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
00492 /* -1 = not valid check */
00493 /* used with join operator */
00494 int area_getorientation(ScrArea *sa, ScrArea *sb)
00495 {
00496     ScrVert *sav1, *sav2, *sav3, *sav4;
00497     ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
00498 
00499     if(sa==NULL || sb==NULL) return -1;
00500 
00501     sav1= sa->v1;
00502     sav2= sa->v2;
00503     sav3= sa->v3;
00504     sav4= sa->v4;
00505     sbv1= sb->v1;
00506     sbv2= sb->v2;
00507     sbv3= sb->v3;
00508     sbv4= sb->v4;
00509     
00510     if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
00511         return 0;
00512     }
00513     else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
00514         return 1;
00515     }
00516     else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
00517         return 2;
00518     }
00519     else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
00520         return 3;
00521     }
00522     
00523     return -1;
00524 }
00525 
00526 /* Helper function to join 2 areas, it has a return value, 0=failed 1=success
00527 *   used by the split, join operators
00528 */
00529 int screen_area_join(bContext *C, bScreen* scr, ScrArea *sa1, ScrArea *sa2) 
00530 {
00531     int dir;
00532     
00533     dir = area_getorientation(sa1, sa2);
00534     /*printf("dir is : %i \n", dir);*/
00535     
00536     if (dir < 0) {
00537         if (sa1 ) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
00538         if (sa2 ) sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
00539         return 0;
00540     }
00541     
00542     if(dir == 0) {
00543         sa1->v1= sa2->v1;
00544         sa1->v2= sa2->v2;
00545         screen_addedge(scr, sa1->v2, sa1->v3);
00546         screen_addedge(scr, sa1->v1, sa1->v4);
00547     }
00548     else if(dir == 1) {
00549         sa1->v2= sa2->v2;
00550         sa1->v3= sa2->v3;
00551         screen_addedge(scr, sa1->v1, sa1->v2);
00552         screen_addedge(scr, sa1->v3, sa1->v4);
00553     }
00554     else if(dir == 2) {
00555         sa1->v3= sa2->v3;
00556         sa1->v4= sa2->v4;
00557         screen_addedge(scr, sa1->v2, sa1->v3);
00558         screen_addedge(scr, sa1->v1, sa1->v4);
00559     }
00560     else if(dir == 3) {
00561         sa1->v1= sa2->v1;
00562         sa1->v4= sa2->v4;
00563         screen_addedge(scr, sa1->v1, sa1->v2);
00564         screen_addedge(scr, sa1->v3, sa1->v4);
00565     }
00566     
00567     screen_delarea(C, scr, sa2);
00568     removedouble_scrverts(scr);
00569     sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
00570     
00571     return 1;
00572 }
00573 
00574 void select_connected_scredge(bScreen *sc, ScrEdge *edge)
00575 {
00576     ScrEdge *se;
00577     ScrVert *sv;
00578     int oneselected;
00579     char dir;
00580     
00581     /* select connected, only in the right direction */
00582     /* 'dir' is the direction of EDGE */
00583     
00584     if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
00585     else dir= 'h';
00586     
00587     sv= sc->vertbase.first;
00588     while(sv) {
00589         sv->flag = 0;
00590         sv= sv->next;
00591     }
00592     
00593     edge->v1->flag= 1;
00594     edge->v2->flag= 1;
00595     
00596     oneselected= 1;
00597     while(oneselected) {
00598         se= sc->edgebase.first;
00599         oneselected= 0;
00600         while(se) {
00601             if(se->v1->flag + se->v2->flag==1) {
00602                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
00603                     se->v1->flag= se->v2->flag= 1;
00604                     oneselected= 1;
00605                 }
00606                     if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
00607                         se->v1->flag= se->v2->flag= 1;
00608                         oneselected= 1;
00609                     }
00610             }
00611                 se= se->next;
00612         }
00613     }
00614 }
00615 
00616 /* test if screen vertices should be scaled */
00617 static void screen_test_scale(bScreen *sc, int winsizex, int winsizey)
00618 {
00619     ScrVert *sv=NULL;
00620     ScrArea *sa;
00621     int sizex, sizey;
00622     float facx, facy, tempf, min[2], max[2];
00623     
00624     /* calculate size */
00625     min[0]= min[1]= 10000.0f;
00626     max[0]= max[1]= 0.0f;
00627     
00628     for(sv= sc->vertbase.first; sv; sv= sv->next) {
00629         min[0]= MIN2(min[0], sv->vec.x);
00630         min[1]= MIN2(min[1], sv->vec.y);
00631         max[0]= MAX2(max[0], sv->vec.x);
00632         max[1]= MAX2(max[1], sv->vec.y);
00633     }
00634     
00635     /* always make 0.0 left under */
00636     for(sv= sc->vertbase.first; sv; sv= sv->next) {
00637         sv->vec.x -= min[0];
00638         sv->vec.y -= min[1];
00639     }
00640     
00641     sizex= max[0]-min[0];
00642     sizey= max[1]-min[1];
00643     
00644     if(sizex!= winsizex || sizey!= winsizey) {
00645         facx= winsizex;
00646         facx/= (float)sizex;
00647         facy= winsizey;
00648         facy/= (float)sizey;
00649         
00650         /* make sure it fits! */
00651         for(sv= sc->vertbase.first; sv; sv= sv->next) {
00652             /* FIXME, this resizing logic is no good when resizing the window + redrawing [#24428]
00653              * need some way to store these as floats internally and re-apply from there. */
00654             tempf= ((float)sv->vec.x)*facx;
00655             sv->vec.x= (short)(tempf+0.5f);
00656             sv->vec.x+= AREAGRID-1;
00657             sv->vec.x-=  (sv->vec.x % AREAGRID); 
00658 
00659             CLAMP(sv->vec.x, 0, winsizex);
00660             
00661             tempf= ((float)sv->vec.y)*facy;
00662             sv->vec.y= (short)(tempf+0.5f);
00663             sv->vec.y+= AREAGRID-1;
00664             sv->vec.y-=  (sv->vec.y % AREAGRID); 
00665 
00666             CLAMP(sv->vec.y, 0, winsizey);
00667         }
00668     }
00669     
00670     /* test for collapsed areas. This could happen in some blender version... */
00671     /* ton: removed option now, it needs Context... */
00672     
00673     /* make each window at least ED_area_headersize() high */
00674     for(sa= sc->areabase.first; sa; sa= sa->next) {
00675         int headery= ED_area_headersize()+1;
00676         
00677         if(sa->v1->vec.y+headery > sa->v2->vec.y) {
00678             /* lower edge */
00679             ScrEdge *se= screen_findedge(sc, sa->v4, sa->v1);
00680             if(se && sa->v1!=sa->v2 ) {
00681                 int yval;
00682                 
00683                 select_connected_scredge(sc, se);
00684                 
00685                 /* all selected vertices get the right offset */
00686                 yval= sa->v2->vec.y-headery;
00687                 sv= sc->vertbase.first;
00688                 while(sv) {
00689                     /* if is a collapsed area */
00690                     if(sv!=sa->v2 && sv!=sa->v3) {
00691                         if(sv->flag) sv->vec.y= yval;
00692                     }
00693                     sv= sv->next;
00694                 }
00695             }
00696         }
00697     }
00698     
00699 }
00700 
00701 /* *********************** DRAWING **************************************** */
00702 
00703 
00704 #define SCR_BACK 0.55
00705 #define SCR_ROUND 12
00706 
00707 /* draw vertical shape visualising future joining (left as well
00708  * right direction of future joining) */
00709 static void draw_horizontal_join_shape(ScrArea *sa, char dir)
00710 {
00711     vec2f points[10];
00712     short i;
00713     float w, h;
00714     float width = sa->v3->vec.x - sa->v1->vec.x;
00715     float height = sa->v3->vec.y - sa->v1->vec.y;
00716 
00717     if(height<width) {
00718         h = height/8;
00719         w = height/4;
00720     }
00721     else {
00722         h = width/8;
00723         w = width/4;
00724     }
00725 
00726     points[0].x = sa->v1->vec.x;
00727     points[0].y = sa->v1->vec.y + height/2;
00728 
00729     points[1].x = sa->v1->vec.x;
00730     points[1].y = sa->v1->vec.y;
00731 
00732     points[2].x = sa->v4->vec.x - w;
00733     points[2].y = sa->v4->vec.y;
00734 
00735     points[3].x = sa->v4->vec.x - w;
00736     points[3].y = sa->v4->vec.y + height/2 - 2*h;
00737 
00738     points[4].x = sa->v4->vec.x - 2*w;
00739     points[4].y = sa->v4->vec.y + height/2;
00740 
00741     points[5].x = sa->v4->vec.x - w;
00742     points[5].y = sa->v4->vec.y + height/2 + 2*h;
00743 
00744     points[6].x = sa->v3->vec.x - w;
00745     points[6].y = sa->v3->vec.y;
00746 
00747     points[7].x = sa->v2->vec.x;
00748     points[7].y = sa->v2->vec.y;
00749 
00750     points[8].x = sa->v4->vec.x;
00751     points[8].y = sa->v4->vec.y + height/2 - h;
00752 
00753     points[9].x = sa->v4->vec.x;
00754     points[9].y = sa->v4->vec.y + height/2 + h;
00755 
00756     if(dir=='l') {
00757         /* when direction is left, then we flip direction of arrow */
00758         float cx = sa->v1->vec.x + width;
00759         for(i=0;i<10;i++) {
00760             points[i].x -= cx;
00761             points[i].x = -points[i].x;
00762             points[i].x += sa->v1->vec.x;
00763         }
00764     }
00765 
00766     glBegin(GL_POLYGON);
00767     for(i=0;i<5;i++)
00768         glVertex2f(points[i].x, points[i].y);
00769     glEnd();
00770     glBegin(GL_POLYGON);
00771     for(i=4;i<8;i++)
00772         glVertex2f(points[i].x, points[i].y);
00773     glVertex2f(points[0].x, points[0].y);
00774     glEnd();
00775 
00776     glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
00777     glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
00778 }
00779 
00780 /* draw vertical shape visualising future joining (up/down direction) */
00781 static void draw_vertical_join_shape(ScrArea *sa, char dir)
00782 {
00783     vec2f points[10];
00784     short i;
00785     float w, h;
00786     float width = sa->v3->vec.x - sa->v1->vec.x;
00787     float height = sa->v3->vec.y - sa->v1->vec.y;
00788 
00789     if(height<width) {
00790         h = height/4;
00791         w = height/8;
00792     }
00793     else {
00794         h = width/4;
00795         w = width/8;
00796     }
00797 
00798     points[0].x = sa->v1->vec.x + width/2;
00799     points[0].y = sa->v3->vec.y;
00800 
00801     points[1].x = sa->v2->vec.x;
00802     points[1].y = sa->v2->vec.y;
00803 
00804     points[2].x = sa->v1->vec.x;
00805     points[2].y = sa->v1->vec.y + h;
00806 
00807     points[3].x = sa->v1->vec.x + width/2 - 2*w;
00808     points[3].y = sa->v1->vec.y + h;
00809 
00810     points[4].x = sa->v1->vec.x + width/2;
00811     points[4].y = sa->v1->vec.y + 2*h;
00812 
00813     points[5].x = sa->v1->vec.x + width/2 + 2*w;
00814     points[5].y = sa->v1->vec.y + h;
00815 
00816     points[6].x = sa->v4->vec.x;
00817     points[6].y = sa->v4->vec.y + h;
00818     
00819     points[7].x = sa->v3->vec.x;
00820     points[7].y = sa->v3->vec.y;
00821 
00822     points[8].x = sa->v1->vec.x + width/2 - w;
00823     points[8].y = sa->v1->vec.y;
00824 
00825     points[9].x = sa->v1->vec.x + width/2 + w;
00826     points[9].y = sa->v1->vec.y;
00827 
00828     if(dir=='u') {
00829         /* when direction is up, then we flip direction of arrow */
00830         float cy = sa->v1->vec.y + height;
00831         for(i=0;i<10;i++) {
00832             points[i].y -= cy;
00833             points[i].y = -points[i].y;
00834             points[i].y += sa->v1->vec.y;
00835         }
00836     }
00837 
00838     glBegin(GL_POLYGON);
00839     for(i=0;i<5;i++)
00840         glVertex2f(points[i].x, points[i].y);
00841     glEnd();
00842     glBegin(GL_POLYGON);
00843     for(i=4;i<8;i++)
00844         glVertex2f(points[i].x, points[i].y);
00845     glVertex2f(points[0].x, points[0].y);
00846     glEnd();
00847 
00848     glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
00849     glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
00850 }
00851 
00852 /* draw join shape due to direction of joining */
00853 static void draw_join_shape(ScrArea *sa, char dir)
00854 {
00855     if(dir=='u' || dir=='d')
00856         draw_vertical_join_shape(sa, dir);
00857     else
00858         draw_horizontal_join_shape(sa, dir);
00859 }
00860 
00861 /* draw screen area darker with arrow (visualisation of future joining) */
00862 static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
00863 {
00864     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00865     glEnable(GL_BLEND);
00866     glColor4ub(0, 0, 0, 50);
00867     draw_join_shape(sa, dir);
00868     glDisable(GL_BLEND);
00869 }
00870 
00871 /* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
00872 static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir))
00873 {
00874     glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
00875     glEnable(GL_BLEND);
00876     /* value 181 was hardly computed: 181~105 */
00877     glColor4ub(255, 255, 255, 50);      
00878     /* draw_join_shape(sa, dir); */
00879     glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
00880     glDisable(GL_BLEND);
00881 }
00882 
00883 static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, short a) 
00884 {
00885     /* right border area */
00886     if(x2<sizex-1)
00887         sdrawline(x2+a, y1, x2+a, y2);
00888     
00889     /* left border area */
00890     if(x1>0)  /* otherwise it draws the emboss of window over */
00891         sdrawline(x1+a, y1, x1+a, y2);
00892     
00893     /* top border area */
00894     if(y2<sizey-1)
00895         sdrawline(x1, y2+a, x2, y2+a);
00896     
00897     /* bottom border area */
00898     if(y1>0)
00899         sdrawline(x1, y1+a, x2, y1+a);
00900     
00901 }
00902 
00904 static void drawscredge_area(ScrArea *sa, int sizex, int sizey, int center)
00905 {
00906     short x1= sa->v1->vec.x;
00907     short y1= sa->v1->vec.y;
00908     short x2= sa->v3->vec.x;
00909     short y2= sa->v3->vec.y;
00910     short a, rt;
00911     
00912     rt= 0; // CLAMPIS(G.rt, 0, 16);
00913     
00914     if(center==0) {
00915         cpack(0x505050);
00916         for(a=-rt; a<=rt; a++)
00917             if(a!=0)
00918                 drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, a);
00919     }
00920     else {
00921         cpack(0x0);
00922         drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, 0);
00923     }
00924 }
00925 
00926 /* ****************** EXPORTED API TO OTHER MODULES *************************** */
00927 
00928 bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
00929 {
00930     bScreen *newsc;
00931     
00932     if(sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
00933     
00934     /* make new empty screen: */
00935     newsc= ED_screen_add(win, sc->scene, sc->id.name+2);
00936     /* copy all data */
00937     screen_copy(newsc, sc);
00938 
00939     return newsc;
00940 }
00941 
00942 /* screen sets cursor based on swinid */
00943 static void region_cursor_set(wmWindow *win, int swinid)
00944 {
00945     ScrArea *sa= win->screen->areabase.first;
00946     
00947     for(;sa; sa= sa->next) {
00948         ARegion *ar= sa->regionbase.first;
00949         for(;ar; ar= ar->next) {
00950             if(ar->swinid == swinid) {
00951                 if(ar->type && ar->type->cursor)
00952                     ar->type->cursor(win, sa, ar);
00953                 else
00954                     WM_cursor_set(win, CURSOR_STD);
00955                 return;
00956             }
00957         }
00958     }
00959 }
00960 
00961 void ED_screen_do_listen(bContext *C, wmNotifier *note)
00962 {
00963     wmWindow *win= CTX_wm_window(C);
00964     
00965     /* generic notes */
00966     switch(note->category) {
00967         case NC_WM:
00968             if(note->data==ND_FILEREAD)
00969                 win->screen->do_draw= 1;
00970             break;
00971         case NC_WINDOW:
00972             win->screen->do_draw= 1;
00973             break;
00974         case NC_SCREEN:
00975             if(note->data==ND_SUBWINACTIVE)
00976                 uiFreeActiveButtons(C, win->screen);
00977             if(note->action==NA_EDITED)
00978                 win->screen->do_draw= win->screen->do_refresh= 1;
00979             break;
00980         case NC_SCENE:
00981             if(note->data==ND_MODE)
00982                 region_cursor_set(win, note->swinid);               
00983             break;
00984     }
00985 }
00986 
00987 /* only for edge lines between areas, and the blended join arrows */
00988 void ED_screen_draw(wmWindow *win)
00989 {
00990     ScrArea *sa;
00991     ScrArea *sa1= NULL;
00992     ScrArea *sa2= NULL;
00993     ScrArea *sa3= NULL;
00994     int dir = -1;
00995     int dira = -1;
00996 
00997     wmSubWindowSet(win, win->screen->mainwin);
00998     
00999     for(sa= win->screen->areabase.first; sa; sa= sa->next) {
01000         if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
01001         if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
01002         if (sa->flag & (AREA_FLAG_DRAWSPLIT_H|AREA_FLAG_DRAWSPLIT_V)) sa3 = sa;
01003         drawscredge_area(sa, win->sizex, win->sizey, 0);
01004     }
01005     for(sa= win->screen->areabase.first; sa; sa= sa->next)
01006         drawscredge_area(sa, win->sizex, win->sizey, 1);
01007     
01008     /* blended join arrow */
01009     if (sa1 && sa2) {
01010         dir = area_getorientation(sa1, sa2);
01011         if (dir >= 0) {
01012             switch(dir) {
01013                 case 0: /* W */
01014                     dir = 'r';
01015                     dira = 'l';
01016                     break;
01017                 case 1: /* N */
01018                     dir = 'd';
01019                     dira = 'u';
01020                     break;
01021                 case 2: /* E */
01022                     dir = 'l';
01023                     dira = 'r';
01024                     break;
01025                 case 3: /* S */
01026                     dir = 'u';
01027                     dira = 'd';
01028                     break;
01029             }
01030         }
01031         scrarea_draw_shape_dark(sa2, dir);
01032         scrarea_draw_shape_light(sa1, dira);
01033     }
01034     
01035     /* splitpoint */
01036     if(sa3) {
01037         glEnable(GL_BLEND);
01038         glColor4ub(255, 255, 255, 100);
01039         
01040         if(sa3->flag & AREA_FLAG_DRAWSPLIT_H) {
01041             sdrawline(sa3->totrct.xmin, win->eventstate->y, sa3->totrct.xmax, win->eventstate->y);
01042             glColor4ub(0, 0, 0, 100);
01043             sdrawline(sa3->totrct.xmin, win->eventstate->y+1, sa3->totrct.xmax, win->eventstate->y+1);
01044         }
01045         else {
01046             sdrawline(win->eventstate->x, sa3->totrct.ymin, win->eventstate->x, sa3->totrct.ymax);
01047             glColor4ub(0, 0, 0, 100);
01048             sdrawline(win->eventstate->x+1, sa3->totrct.ymin, win->eventstate->x+1, sa3->totrct.ymax);
01049         }
01050         
01051         glDisable(GL_BLEND);
01052     }
01053     
01054     win->screen->do_draw= 0;
01055 }
01056 
01057 /* helper call for below, dpi changes headers */
01058 static void screen_refresh_headersizes(void)
01059 {
01060     const ListBase *lb= BKE_spacetypes_list();
01061     SpaceType *st;
01062     
01063     for(st= lb->first; st; st= st->next) {
01064         ARegionType *art= BKE_regiontype_from_id(st, RGN_TYPE_HEADER);
01065         if(art) art->prefsizey= ED_area_headersize();
01066     }       
01067 }
01068 
01069 /* make this screen usable */
01070 /* for file read and first use, for scaling window, area moves */
01071 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
01072 {   
01073     /* exception for bg mode, we only need the screen context */
01074     if (!G.background) {
01075         ScrArea *sa;
01076         rcti winrct;
01077     
01078         winrct.xmin= 0;
01079         winrct.xmax= win->sizex-1;
01080         winrct.ymin= 0;
01081         winrct.ymax= win->sizey-1;
01082         
01083         screen_test_scale(win->screen, win->sizex, win->sizey);
01084         
01085         if(win->screen->mainwin==0)
01086             win->screen->mainwin= wm_subwindow_open(win, &winrct);
01087         else
01088             wm_subwindow_position(win, win->screen->mainwin, &winrct);
01089         
01090         /* header size depends on DPI, let's verify */
01091         screen_refresh_headersizes();
01092         
01093         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
01094             /* set spacetype and region callbacks, calls init() */
01095             /* sets subwindows for regions, adds handlers */
01096             ED_area_initialize(wm, win, sa);
01097         }
01098     
01099         /* wake up animtimer */
01100         if(win->screen->animtimer)
01101             WM_event_timer_sleep(wm, win, win->screen->animtimer, 0);
01102     }
01103 
01104     if(G.f & G_DEBUG) printf("set screen\n");
01105     win->screen->do_refresh= 0;
01106 
01107     win->screen->context= ed_screen_context;
01108 }
01109 
01110 /* file read, set all screens, ... */
01111 void ED_screens_initialize(wmWindowManager *wm)
01112 {
01113     wmWindow *win;
01114     
01115     for(win= wm->windows.first; win; win= win->next) {
01116         
01117         if(win->screen==NULL)
01118             win->screen= G.main->screen.first;
01119         
01120         ED_screen_refresh(wm, win);
01121     }
01122 }
01123 
01124 
01125 /* *********** exit calls are for closing running stuff ******** */
01126 
01127 void ED_region_exit(bContext *C, ARegion *ar)
01128 {
01129     ARegion *prevar= CTX_wm_region(C);
01130 
01131     CTX_wm_region_set(C, ar);
01132     WM_event_remove_handlers(C, &ar->handlers);
01133     if(ar->swinid)
01134         wm_subwindow_close(CTX_wm_window(C), ar->swinid);
01135     ar->swinid= 0;
01136     
01137     if(ar->headerstr)
01138         MEM_freeN(ar->headerstr);
01139     ar->headerstr= NULL;
01140     
01141     CTX_wm_region_set(C, prevar);
01142 }
01143 
01144 void ED_area_exit(bContext *C, ScrArea *sa)
01145 {
01146     ScrArea *prevsa= CTX_wm_area(C);
01147     ARegion *ar;
01148 
01149     if (sa->spacetype == SPACE_FILE) {
01150         SpaceLink *sl= sa->spacedata.first;
01151         if(sl && sl->spacetype == SPACE_FILE) {
01152             ED_fileselect_exit(C, (SpaceFile *)sl);
01153         }
01154     }
01155 
01156     CTX_wm_area_set(C, sa);
01157     for(ar= sa->regionbase.first; ar; ar= ar->next)
01158         ED_region_exit(C, ar);
01159 
01160     WM_event_remove_handlers(C, &sa->handlers);
01161     CTX_wm_area_set(C, prevsa);
01162 }
01163 
01164 void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
01165 {
01166     wmWindowManager *wm= CTX_wm_manager(C);
01167     wmWindow *prevwin= CTX_wm_window(C);
01168     ScrArea *sa;
01169     ARegion *ar;
01170 
01171     CTX_wm_window_set(C, window);
01172     
01173     if(screen->animtimer)
01174         WM_event_remove_timer(wm, window, screen->animtimer);
01175     screen->animtimer= NULL;
01176     
01177     if(screen->mainwin)
01178         wm_subwindow_close(window, screen->mainwin);
01179     screen->mainwin= 0;
01180     screen->subwinactive= 0;
01181     
01182     for(ar= screen->regionbase.first; ar; ar= ar->next)
01183         ED_region_exit(C, ar);
01184 
01185     for(sa= screen->areabase.first; sa; sa= sa->next)
01186         ED_area_exit(C, sa);
01187 
01188     /* mark it available for use for other windows */
01189     screen->winid= 0;
01190     
01191     if (prevwin->screen->temp == 0) {
01192         /* use previous window if possible */
01193         CTX_wm_window_set(C, prevwin);
01194     } else {
01195         /* none otherwise */
01196         CTX_wm_window_set(C, NULL);
01197     }
01198     
01199 }
01200 
01201 /* *********************************** */
01202 
01203 /* case when on area-edge or in azones, or outside window */
01204 static void screen_cursor_set(wmWindow *win, wmEvent *event)
01205 {
01206     AZone *az= NULL;
01207     ScrArea *sa;
01208     
01209     for(sa= win->screen->areabase.first; sa; sa= sa->next)
01210         if((az=is_in_area_actionzone(sa, event->x, event->y)))
01211             break;
01212     
01213     if(sa) {
01214         if(az->type==AZONE_AREA)
01215             WM_cursor_set(win, CURSOR_EDIT);
01216         else if(az->type==AZONE_REGION) {
01217             if(az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT)
01218                 WM_cursor_set(win, CURSOR_X_MOVE);
01219             else
01220                 WM_cursor_set(win, CURSOR_Y_MOVE);
01221         }
01222     }
01223     else {
01224         ScrEdge *actedge= screen_find_active_scredge(win->screen, event->x, event->y);
01225         
01226         if (actedge) {
01227             if(scredge_is_horizontal(actedge))
01228                 WM_cursor_set(win, CURSOR_Y_MOVE);
01229             else
01230                 WM_cursor_set(win, CURSOR_X_MOVE);
01231         }
01232         else
01233             WM_cursor_set(win, CURSOR_STD);
01234     } 
01235 }
01236 
01237 
01238 /* called in wm_event_system.c. sets state vars in screen, cursors */
01239 /* event type is mouse move */
01240 void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
01241 {
01242     wmWindow *win= CTX_wm_window(C);
01243     
01244     if(win->screen) {
01245         bScreen *scr= win->screen;
01246         ScrArea *sa;
01247         ARegion *ar;
01248         int oldswin= scr->subwinactive;
01249 
01250         for(sa= scr->areabase.first; sa; sa= sa->next) {
01251             if(event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
01252                 if(event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
01253                     if(NULL==is_in_area_actionzone(sa, event->x, event->y))
01254                         break;
01255         }
01256         if(sa) {
01257             for(ar= sa->regionbase.first; ar; ar= ar->next) {
01258                 if(BLI_in_rcti(&ar->winrct, event->x, event->y))
01259                     scr->subwinactive= ar->swinid;
01260             }
01261         }
01262         else
01263             scr->subwinactive= scr->mainwin;
01264         
01265         /* check for redraw headers */
01266         if(oldswin!=scr->subwinactive) {
01267 
01268             for(sa= scr->areabase.first; sa; sa= sa->next) {
01269                 int do_draw= 0;
01270                 
01271                 for(ar= sa->regionbase.first; ar; ar= ar->next)
01272                     if(ar->swinid==oldswin || ar->swinid==scr->subwinactive)
01273                         do_draw= 1;
01274                 
01275                 if(do_draw) {
01276                     for(ar= sa->regionbase.first; ar; ar= ar->next)
01277                         if(ar->regiontype==RGN_TYPE_HEADER)
01278                             ED_region_tag_redraw(ar);
01279                 }
01280             }
01281         }
01282         
01283         /* cursors, for time being set always on edges, otherwise aregion doesnt switch */
01284         if(scr->subwinactive==scr->mainwin) {
01285             screen_cursor_set(win, event);
01286         }
01287         else if(oldswin!=scr->subwinactive) {
01288             region_cursor_set(win, scr->subwinactive);
01289             WM_event_add_notifier(C, NC_SCREEN|ND_SUBWINACTIVE, scr);
01290         }
01291     }
01292 }
01293 
01294 int ED_screen_area_active(const bContext *C)
01295 {
01296     wmWindow *win= CTX_wm_window(C);
01297     bScreen *sc= CTX_wm_screen(C);
01298     ScrArea *sa= CTX_wm_area(C);
01299 
01300     if(win && sc && sa) {
01301         AZone *az= is_in_area_actionzone(sa, win->eventstate->x, win->eventstate->y);
01302         ARegion *ar;
01303         
01304         if (az && az->type == AZONE_REGION)
01305             return 1;
01306         
01307         for(ar= sa->regionbase.first; ar; ar= ar->next)
01308             if(ar->swinid == sc->subwinactive)
01309                 return 1;
01310     }   
01311     return 0;
01312 }
01313 
01314 /* operator call, WM + Window + screen already existed before */
01315 /* Do NOT call in area/region queues! */
01316 void ED_screen_set(bContext *C, bScreen *sc)
01317 {
01318     wmWindowManager *wm= CTX_wm_manager(C);
01319     wmWindow *win= CTX_wm_window(C);
01320     bScreen *oldscreen= CTX_wm_screen(C);
01321     ID *id;
01322     
01323     /* validate screen, it's called with notifier reference */
01324     for(id= CTX_data_main(C)->screen.first; id; id= id->next)
01325         if(sc == (bScreen *)id)
01326             break;
01327     if(id==NULL) 
01328         return;
01329     
01330     /* check for valid winid */
01331     if(sc->winid!=0 && sc->winid!=win->winid)
01332         return;
01333     
01334     if(sc->full) {              /* find associated full */
01335         bScreen *sc1;
01336         for(sc1= CTX_data_main(C)->screen.first; sc1; sc1= sc1->id.next) {
01337             ScrArea *sa= sc1->areabase.first;
01338             if(sa->full==sc) {
01339                 sc= sc1;
01340                 break;
01341             }
01342         }
01343     }
01344     
01345     if (oldscreen != sc) {
01346         wmTimer *wt= oldscreen->animtimer;
01347         ScrArea *sa;
01348 
01349         /* remove handlers referencing areas in old screen */
01350         for(sa = oldscreen->areabase.first; sa; sa = sa->next) {
01351             WM_event_remove_area_handler(&win->modalhandlers, sa);
01352         }
01353 
01354         /* we put timer to sleep, so screen_exit has to think there's no timer */
01355         oldscreen->animtimer= NULL;
01356         if(wt)
01357             WM_event_timer_sleep(wm, win, wt, 1);
01358         
01359         ED_screen_exit(C, win, oldscreen);
01360         oldscreen->animtimer= wt;
01361         
01362         win->screen= sc;
01363         CTX_wm_window_set(C, win);  // stores C->wm.screen... hrmf
01364         
01365         /* prevent multiwin errors */
01366         sc->winid= win->winid;
01367         
01368         ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
01369         WM_event_add_notifier(C, NC_WINDOW, NULL);
01370         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENSET, sc);
01371         
01372         /* makes button hilites work */
01373         WM_event_add_mousemove(C);
01374     }
01375 }
01376 
01377 static int ed_screen_used(wmWindowManager *wm, bScreen *sc)
01378 {
01379     wmWindow *win;
01380 
01381     for(win=wm->windows.first; win; win=win->next)
01382         if(win->screen == sc)
01383             return 1;
01384     
01385     return 0;
01386 }
01387 
01388 /* only call outside of area/region loops */
01389 void ED_screen_delete(bContext *C, bScreen *sc)
01390 {
01391     Main *bmain= CTX_data_main(C);
01392     wmWindowManager *wm= CTX_wm_manager(C);
01393     wmWindow *win= CTX_wm_window(C);
01394     bScreen *newsc;
01395     int delete= 1;
01396     
01397     /* don't allow deleting temp fullscreens for now */
01398     if (sc->full == SCREENFULL) {
01399         return;
01400     }
01401     
01402         
01403     /* screen can only be in use by one window at a time, so as
01404        long as we are able to find a screen that is unused, we
01405        can safely assume ours is not in use anywhere an delete it */
01406 
01407     for(newsc= sc->id.prev; newsc; newsc=newsc->id.prev)
01408         if(!ed_screen_used(wm, newsc))
01409             break;
01410     
01411     if(!newsc) {
01412         for(newsc= sc->id.next; newsc; newsc=newsc->id.next)
01413             if(!ed_screen_used(wm, newsc))
01414                 break;
01415     }
01416 
01417     if(!newsc)
01418         return;
01419 
01420     ED_screen_set(C, newsc);
01421 
01422     if(delete && win->screen != sc)
01423         free_libblock(&bmain->screen, sc);
01424 }
01425 
01426 /* only call outside of area/region loops */
01427 void ED_screen_set_scene(bContext *C, Scene *scene)
01428 {
01429     Main *bmain= CTX_data_main(C);
01430     bScreen *sc;
01431     bScreen *curscreen= CTX_wm_screen(C);
01432     
01433     ED_object_exit_editmode(C, EM_FREEDATA|EM_DO_UNDO);
01434 
01435     for(sc= CTX_data_main(C)->screen.first; sc; sc= sc->id.next) {
01436         if((U.flag & USER_SCENEGLOBAL) || sc==curscreen) {
01437             
01438             if(scene != sc->scene) {
01439                 /* all areas endlocalview */
01440             // XXX  ScrArea *sa= sc->areabase.first;
01441             //  while(sa) {
01442             //      endlocalview(sa);
01443             //      sa= sa->next;
01444             //  }       
01445                 sc->scene= scene;
01446             }
01447             
01448         }
01449     }
01450     
01451     //  copy_view3d_lock(0);    /* space.c */
01452     
01453     /* are there cameras in the views that are not in the scene? */
01454     for(sc= CTX_data_main(C)->screen.first; sc; sc= sc->id.next) {
01455         if( (U.flag & USER_SCENEGLOBAL) || sc==curscreen) {
01456             ScrArea *sa= sc->areabase.first;
01457             while(sa) {
01458                 SpaceLink *sl= sa->spacedata.first;
01459                 while(sl) {
01460                     if(sl->spacetype==SPACE_VIEW3D) {
01461                         View3D *v3d= (View3D*) sl;
01462 
01463                         BKE_screen_view3d_sync(v3d, scene);
01464 
01465                         if (!v3d->camera || !object_in_scene(v3d->camera, scene)) {
01466                             v3d->camera= scene_find_camera(sc->scene);
01467                             // XXX if (sc==curscreen) handle_view3d_lock();
01468                             if (!v3d->camera) {
01469                                 ARegion *ar;
01470                                 for(ar=v3d->regionbase.first; ar; ar= ar->next) {
01471                                     if(ar->regiontype == RGN_TYPE_WINDOW) {
01472                                         RegionView3D *rv3d= ar->regiondata;
01473 
01474                                         if(rv3d->persp==RV3D_CAMOB)
01475                                             rv3d->persp= RV3D_PERSP;
01476                                     }
01477                                 }
01478                             }
01479                         }
01480                     }
01481                     sl= sl->next;
01482                 }
01483                 sa= sa->next;
01484             }
01485         }
01486     }
01487     
01488     CTX_data_scene_set(C, scene);
01489     set_scene_bg(bmain, scene);
01490     
01491     ED_render_engine_changed(bmain);
01492     ED_update_for_newframe(bmain, scene, curscreen, 1);
01493     
01494     /* complete redraw */
01495     WM_event_add_notifier(C, NC_WINDOW, NULL);
01496     
01497 }
01498 
01499 /* only call outside of area/region loops */
01500 void ED_screen_delete_scene(bContext *C, Scene *scene)
01501 {
01502     Main *bmain= CTX_data_main(C);
01503     Scene *newscene;
01504 
01505     if(scene->id.prev)
01506         newscene= scene->id.prev;
01507     else if(scene->id.next)
01508         newscene= scene->id.next;
01509     else
01510         return;
01511 
01512     ED_screen_set_scene(C, newscene);
01513 
01514     unlink_scene(bmain, scene, newscene);
01515 }
01516 
01517 ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
01518 {
01519     wmWindow *win= CTX_wm_window(C);
01520     bScreen *screen= CTX_wm_screen(C);
01521     ScrArea *newsa= NULL;
01522 
01523     if(!sa || sa->full==NULL) {
01524         newsa= ED_screen_full_toggle(C, win, sa);
01525     }
01526     
01527     if(!newsa) {
01528         if (sa->full) {
01529             /* if this has been called from the temporary info header generated in
01530              * temp fullscreen layouts, find the correct fullscreen area to change
01531              * to create a new space inside */
01532             for (newsa = screen->areabase.first; newsa; newsa=newsa->next) {
01533                 if (!(sa->flag & AREA_TEMP_INFO))
01534                     break;
01535             }
01536         } else
01537             newsa= sa;
01538     }
01539     
01540     ED_area_newspace(C, newsa, type);
01541     
01542     return newsa;
01543 }
01544 
01545 void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
01546 {
01547     wmWindow *win= CTX_wm_window(C);
01548 
01549     ED_area_prevspace(C, sa);
01550     
01551     if(sa->full)
01552         ED_screen_full_toggle(C, win, sa);
01553 }
01554 
01555 /* restore a screen / area back to default operation, after temp fullscreen modes */
01556 void ED_screen_full_restore(bContext *C, ScrArea *sa)
01557 {
01558     wmWindow *win= CTX_wm_window(C);
01559     SpaceLink *sl = sa->spacedata.first;
01560     
01561     /* if fullscreen area has a secondary space (such as a file browser or fullscreen render 
01562      * overlaid on top of a existing setup) then return to the previous space */
01563     
01564     if (sl->next) {
01565         /* specific checks for space types */
01566 
01567         int sima_restore = 0;
01568 
01569         /* Special check added for non-render image window (back from fullscreen through "Back to Previous" button) */
01570         if (sl->spacetype == SPACE_IMAGE) {
01571             SpaceImage *sima= sa->spacedata.first;
01572             if (!(sima->flag & SI_PREVSPACE) && !(sima->flag & SI_FULLWINDOW))
01573                 sima_restore = 1;
01574         }
01575 
01576         if (sl->spacetype == SPACE_IMAGE && !sima_restore) {
01577             SpaceImage *sima= sa->spacedata.first;
01578             if (sima->flag & SI_PREVSPACE)
01579                 sima->flag &= ~SI_PREVSPACE;
01580             if (sima->flag & SI_FULLWINDOW) {
01581                 sima->flag &= ~SI_FULLWINDOW;
01582                 ED_screen_full_prevspace(C, sa);
01583             }
01584         } else if (sl->spacetype == SPACE_FILE) {
01585             ED_screen_full_prevspace(C, sa);
01586         } else
01587             ED_screen_full_toggle(C, win, sa);
01588     }
01589     /* otherwise just tile the area again */
01590     else {
01591         ED_screen_full_toggle(C, win, sa);
01592     }
01593 }
01594 
01595 /* this function toggles: if area is full then the parent will be restored */
01596 ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
01597 {
01598     bScreen *sc, *oldscreen;
01599     ARegion *ar;
01600 
01601     if(sa) {
01602         /* ensure we don't have a button active anymore, can crash when
01603            switching screens with tooltip open because region and tooltip
01604            are no longer in the same screen */
01605         for(ar=sa->regionbase.first; ar; ar=ar->next)
01606             uiFreeBlocks(C, &ar->uiblocks);
01607         
01608         /* prevent hanging header prints */
01609         ED_area_headerprint(sa, NULL);
01610     }
01611 
01612     if(sa && sa->full) {
01613         ScrArea *old;
01614         /*short fulltype;*/ /*UNUSED*/
01615 
01616         sc= sa->full;       /* the old screen to restore */
01617         oldscreen= win->screen; /* the one disappearing */
01618 
01619         /*fulltype = sc->full;*/
01620         sc->full= 0;
01621 
01622         /* removed: SCREENAUTOPLAY exception here */
01623     
01624         /* find old area */
01625         for(old= sc->areabase.first; old; old= old->next)
01626             if(old->full) break;
01627         if(old==NULL) {
01628             if (G.f & G_DEBUG)
01629                 printf("something wrong in areafullscreen\n");
01630             return NULL;
01631         }
01632 
01633         area_copy_data(old, sa, 1); /*  1 = swap spacelist */
01634         if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO;
01635         old->full= NULL;
01636 
01637         /* animtimer back */
01638         sc->animtimer= oldscreen->animtimer;
01639         oldscreen->animtimer= NULL;
01640 
01641         ED_screen_set(C, sc);
01642 
01643         free_screen(oldscreen);
01644         free_libblock(&CTX_data_main(C)->screen, oldscreen);
01645 
01646     }
01647     else {
01648         ScrArea *newa;
01649         char newname[MAX_ID_NAME-2];
01650 
01651         oldscreen= win->screen;
01652 
01653         /* nothing wrong with having only 1 area, as far as I can see...
01654         // is there only 1 area?
01655         if(oldscreen->areabase.first==oldscreen->areabase.last)
01656             return NULL;
01657         */
01658 
01659         oldscreen->full = SCREENFULL;
01660         BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name+2, "full");
01661         sc= ED_screen_add(win, oldscreen->scene, newname);
01662         sc->full = SCREENFULL; // XXX
01663 
01664         /* timer */
01665         sc->animtimer= oldscreen->animtimer;
01666         oldscreen->animtimer= NULL;
01667 
01668         /* returns the top small area */
01669         newa= area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
01670         ED_area_newspace(C, newa, SPACE_INFO);
01671 
01672         /* use random area when we have no active one, e.g. when the
01673            mouse is outside of the window and we open a file browser */
01674         if(!sa)
01675             sa= oldscreen->areabase.first;
01676 
01677         /* copy area */
01678         newa= newa->prev;
01679         area_copy_data(newa, sa, 1);    /* 1 = swap spacelist */
01680         sa->flag |= AREA_TEMP_INFO;
01681 
01682         sa->full= oldscreen;
01683         newa->full= oldscreen;
01684         newa->next->full= oldscreen; // XXX
01685 
01686         ED_screen_set(C, sc);
01687     }
01688 
01689     /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
01690     CTX_wm_area_set(C, sc->areabase.first);
01691 
01692     return sc->areabase.first;
01693 }
01694 
01695 /* update frame rate info for viewport drawing */
01696 void ED_refresh_viewport_fps(bContext *C)
01697 {
01698     wmTimer *animtimer= CTX_wm_screen(C)->animtimer;
01699     Scene *scene= CTX_data_scene(C);
01700     
01701     /* is anim playback running? */
01702     if (animtimer && (U.uiflag & USER_SHOW_FPS)) {
01703         ScreenFrameRateInfo *fpsi= scene->fps_info;
01704         
01705         /* if there isn't any info, init it first */
01706         if (fpsi == NULL)
01707             fpsi= scene->fps_info= MEM_callocN(sizeof(ScreenFrameRateInfo), "refresh_viewport_fps fps_info");
01708         
01709         /* update the values */
01710         fpsi->redrawtime= fpsi->lredrawtime;
01711         fpsi->lredrawtime= animtimer->ltime;
01712     }
01713     else {  
01714         /* playback stopped or shouldn't be running */
01715         if (scene->fps_info)
01716             MEM_freeN(scene->fps_info);
01717         scene->fps_info= NULL;
01718     }
01719 }
01720 
01721 /* redraws: uses defines from stime->redraws 
01722  * enable: 1 - forward on, -1 - backwards on, 0 - off
01723  */
01724 void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync, int enable)
01725 {
01726     bScreen *screen= CTX_wm_screen(C);
01727     wmWindowManager *wm= CTX_wm_manager(C);
01728     wmWindow *win= CTX_wm_window(C);
01729     Scene *scene= CTX_data_scene(C);
01730     
01731     if(screen->animtimer)
01732         WM_event_remove_timer(wm, win, screen->animtimer);
01733     screen->animtimer= NULL;
01734     
01735     if(enable) {
01736         ScreenAnimData *sad= MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData");
01737         
01738         screen->animtimer= WM_event_add_timer(wm, win, TIMER0, (1.0/FPS));
01739         
01740         sad->ar= CTX_wm_region(C);
01741         sad->sfra = scene->r.cfra;
01742         sad->redraws= redraws;
01743         sad->refresh= refresh;
01744         sad->flag |= (enable < 0)? ANIMPLAY_FLAG_REVERSE: 0;
01745         sad->flag |= (sync == 0)? ANIMPLAY_FLAG_NO_SYNC: (sync == 1)? ANIMPLAY_FLAG_SYNC: 0;
01746         
01747         screen->animtimer->customdata= sad;
01748         
01749     }
01750     /* notifier catched by top header, for button */
01751     WM_event_add_notifier(C, NC_SCREEN|ND_ANIMPLAY, screen);
01752 }
01753 
01754 /* helper for screen_animation_play() - only to be used for TimeLine */
01755 static ARegion *time_top_left_3dwindow(bScreen *screen)
01756 {
01757     ARegion *aret= NULL;
01758     ScrArea *sa;
01759     int min= 10000;
01760     
01761     for(sa= screen->areabase.first; sa; sa= sa->next) {
01762         if(sa->spacetype==SPACE_VIEW3D) {
01763             ARegion *ar;
01764             for(ar= sa->regionbase.first; ar; ar= ar->next) {
01765                 if(ar->regiontype==RGN_TYPE_WINDOW) {
01766                     if(ar->winrct.xmin - ar->winrct.ymin < min) {
01767                         aret= ar;
01768                         min= ar->winrct.xmin - ar->winrct.ymin;
01769                     }
01770                 }
01771             }
01772         }
01773     }
01774 
01775     return aret;
01776 }
01777 
01778 void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh)
01779 {
01780     if(screen && screen->animtimer) {
01781         wmTimer *wt= screen->animtimer;
01782         ScreenAnimData *sad= wt->customdata;
01783         
01784         sad->redraws= redraws;
01785         sad->refresh= refresh;
01786         sad->ar= NULL;
01787         if(redraws & TIME_REGION)
01788             sad->ar= time_top_left_3dwindow(screen);
01789     }
01790 }
01791 
01792 /* results in fully updated anim system
01793  * screen can be NULL */
01794 void ED_update_for_newframe(Main *bmain, Scene *scene, bScreen *screen, int UNUSED(mute))
01795 {   
01796 #ifdef DURIAN_CAMERA_SWITCH
01797     void *camera= scene_camera_switch_find(scene);
01798     if(camera && scene->camera != camera) {
01799         bScreen *sc;
01800         scene->camera= camera;
01801         /* are there cameras in the views that are not in the scene? */
01802         for(sc= bmain->screen.first; sc; sc= sc->id.next) {
01803             BKE_screen_view3d_scene_sync(sc);
01804         }
01805     }
01806 #endif
01807 
01808     //extern void audiostream_scrub(unsigned int frame);    /* seqaudio.c */
01809     
01810     /* update animated image textures for gpu, etc,
01811      * call before scene_update_for_newframe so modifiers with textuers dont lag 1 frame */
01812     ED_image_update_frame(bmain, scene->r.cfra);
01813 
01814     ED_clip_update_frame(bmain, scene->r.cfra);
01815 
01816     /* this function applies the changes too */
01817     /* XXX future: do all windows */
01818     scene_update_for_newframe(bmain, scene, BKE_screen_visible_layers(screen, scene)); /* BKE_scene.h */
01819     
01820     //if ( (CFRA>1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB)) 
01821     //  audiostream_scrub( CFRA );
01822     
01823     /* 3d window, preview */
01824     //BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
01825     
01826     /* all movie/sequence images */
01827     //BIF_image_update_frame();
01828     
01829     /* composite */
01830     if(scene->use_nodes && scene->nodetree)
01831         ntreeCompositTagAnimated(scene->nodetree);
01832     
01833     /* update animated texture nodes */
01834     {
01835         Tex *tex;
01836         for(tex= bmain->tex.first; tex; tex= tex->id.next)
01837             if( tex->use_nodes && tex->nodetree ) {
01838                 ntreeTexTagAnimated( tex->nodetree );
01839             }
01840     }
01841     
01842 }
01843 
01844