Blender  V2.59
area.c
Go to the documentation of this file.
00001 /*
00002  * $Id: area.c 37986 2011-06-30 15:02:03Z ton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2008 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * 
00024  * Contributor(s): Blender Foundation
00025  *
00026  * ***** END GPL LICENSE BLOCK *****
00027  */
00028 
00034 #include <string.h>
00035 #include <stdio.h>
00036 
00037 #include "MEM_guardedalloc.h"
00038 
00039 #include "DNA_userdef_types.h"
00040 
00041 #include "BLI_blenlib.h"
00042 #include "BLI_math.h"
00043 #include "BLI_rand.h"
00044 #include "BLI_utildefines.h"
00045 
00046 #include "BKE_context.h"
00047 #include "BKE_global.h"
00048 #include "BKE_screen.h"
00049 
00050 #include "WM_api.h"
00051 #include "WM_types.h"
00052 #include "wm_subwindow.h"
00053 
00054 #include "ED_screen.h"
00055 #include "ED_screen_types.h"
00056 #include "ED_space_api.h"
00057 #include "ED_types.h"
00058 #include "ED_fileselect.h" 
00059 
00060 #include "BIF_gl.h"
00061 #include "BIF_glutil.h"
00062 #include "BLF_api.h"
00063 
00064 #include "UI_interface.h"
00065 #include "UI_resources.h"
00066 #include "UI_view2d.h"
00067 
00068 #include "screen_intern.h"
00069 
00070 /* general area and region code */
00071 
00072 static void region_draw_emboss(ARegion *ar, rcti *scirct)
00073 {
00074         rcti rect;
00075         
00076         /* translate scissor rect to region space */
00077         rect.xmin= scirct->xmin - ar->winrct.xmin;
00078         rect.ymin= scirct->ymin - ar->winrct.ymin;
00079         rect.xmax= scirct->xmax - ar->winrct.xmin;
00080         rect.ymax= scirct->ymax - ar->winrct.ymin;
00081         
00082         /* set transp line */
00083         glEnable( GL_BLEND );
00084         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00085         
00086         /* right  */
00087         glColor4ub(0,0,0, 50);
00088         sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax);
00089         
00090         /* bottom  */
00091         glColor4ub(0,0,0, 80);
00092         sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin);
00093         
00094         /* top  */
00095         glColor4ub(255,255,255, 60);
00096         sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax);
00097 
00098         /* left  */
00099         glColor4ub(255,255,255, 50);
00100         sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax);
00101         
00102         glDisable( GL_BLEND );
00103 }
00104 
00105 void ED_region_pixelspace(ARegion *ar)
00106 {
00107         int width= ar->winrct.xmax-ar->winrct.xmin+1;
00108         int height= ar->winrct.ymax-ar->winrct.ymin+1;
00109         
00110         wmOrtho2(-0.375f, (float)width-0.375f, -0.375f, (float)height-0.375f);
00111         glLoadIdentity();
00112 }
00113 
00114 /* only exported for WM */
00115 void ED_region_do_listen(ARegion *ar, wmNotifier *note)
00116 {
00117         /* generic notes first */
00118         switch(note->category) {
00119                 case NC_WM:
00120                         if(note->data==ND_FILEREAD)
00121                                 ED_region_tag_redraw(ar);
00122                         break;
00123                 case NC_WINDOW:
00124                         ED_region_tag_redraw(ar);
00125                         break;
00126         }
00127 
00128         if(ar->type && ar->type->listener)
00129                 ar->type->listener(ar, note);
00130 }
00131 
00132 /* only exported for WM */
00133 void ED_area_do_listen(ScrArea *sa, wmNotifier *note)
00134 {
00135         /* no generic notes? */
00136         if(sa->type && sa->type->listener) {
00137                 sa->type->listener(sa, note);
00138         }
00139 }
00140 
00141 /* only exported for WM */
00142 void ED_area_do_refresh(bContext *C, ScrArea *sa)
00143 {
00144         /* no generic notes? */
00145         if(sa->type && sa->type->refresh) {
00146                 sa->type->refresh(C, sa);
00147         }
00148         sa->do_refresh= 0;
00149 }
00150 
00151 /* based on screen region draw tags, set draw tags in azones, and future region tabs etc */
00152 /* only exported for WM */
00153 void ED_area_overdraw_flush(ScrArea *sa, ARegion *ar)
00154 {
00155         AZone *az;
00156         
00157         for(az= sa->actionzones.first; az; az= az->next) {
00158                 int xs, ys;
00159                 
00160                 xs= (az->x1+az->x2)/2;
00161                 ys= (az->y1+az->y2)/2;
00162 
00163                 /* test if inside */
00164                 if(BLI_in_rcti(&ar->winrct, xs, ys)) {
00165                         az->do_draw= 1;
00166                 }
00167         }
00168 }
00169 
00170 static void area_draw_azone(short x1, short y1, short x2, short y2)
00171 {
00172         int dx= floor(0.3f*(x2-x1));
00173         int dy= floor(0.3f*(y2-y1));
00174         
00175         glColor4ub(255, 255, 255, 180);
00176         fdrawline(x1, y2, x2, y1);
00177         glColor4ub(255, 255, 255, 130);
00178         fdrawline(x1, y2-dy, x2-dx, y1);
00179         glColor4ub(255, 255, 255, 80);
00180         fdrawline(x1, y2-2*dy, x2-2*dx, y1);
00181         
00182         glColor4ub(0, 0, 0, 210);
00183         fdrawline(x1, y2+1, x2+1, y1);
00184         glColor4ub(0, 0, 0, 180);
00185         fdrawline(x1, y2-dy+1, x2-dx+1, y1);
00186         glColor4ub(0, 0, 0, 150);
00187         fdrawline(x1, y2-2*dy+1, x2-2*dx+1, y1);
00188 }
00189 
00190 
00191 static void region_draw_azone_icon(AZone *az)
00192 {
00193         GLUquadricObj *qobj = NULL; 
00194         short midx = az->x1 + (az->x2 - az->x1)/2;
00195         short midy = az->y1 + (az->y2 - az->y1)/2;
00196                 
00197         qobj = gluNewQuadric();
00198         
00199         glPushMatrix();         
00200         glTranslatef(midx, midy, 0.); 
00201         
00202         /* outlined circle */
00203         glEnable(GL_LINE_SMOOTH);
00204 
00205         glColor4f(1.f, 1.f, 1.f, 0.8f);
00206 
00207         gluQuadricDrawStyle(qobj, GLU_FILL); 
00208         gluDisk( qobj, 0.0,  4.25f, 16, 1); 
00209 
00210         glColor4f(0.2f, 0.2f, 0.2f, 0.9f);
00211         
00212         gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); 
00213         gluDisk( qobj, 0.0,  4.25f, 16, 1); 
00214         
00215         glDisable(GL_LINE_SMOOTH);
00216         
00217         glPopMatrix();
00218         gluDeleteQuadric(qobj);
00219         
00220         /* + */
00221         sdrawline(midx, midy-2, midx, midy+3);
00222         sdrawline(midx-2, midy, midx+3, midy);
00223 }
00224 
00225 static void region_draw_azone_tab(AZone *az)
00226 {
00227         float col[3];
00228         
00229         glEnable(GL_BLEND);
00230         UI_GetThemeColor3fv(TH_HEADER, col);
00231         glColor4f(col[0], col[1], col[2], 0.5f);
00232         
00233         /* add code to draw region hidden as 'too small' */
00234         switch(az->edge) {
00235                 case AE_TOP_TO_BOTTOMRIGHT:
00236                         uiSetRoundBox(3 + 16);
00237                         
00238                         uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
00239                         glColor4ub(0, 0, 0, 255);
00240                         uiRoundRect((float)az->x1, 0.3f+(float)az->y1, (float)az->x2, 0.3f+(float)az->y2, 4.0f);
00241                         break;
00242                 case AE_BOTTOM_TO_TOPLEFT:
00243                         uiSetRoundBox(12 + 16);
00244                         
00245                         uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
00246                         glColor4ub(0, 0, 0, 255);
00247                         uiRoundRect((float)az->x1, 0.3f+(float)az->y1, (float)az->x2, 0.3f+(float)az->y2, 4.0f);
00248                         break;
00249                 case AE_LEFT_TO_TOPRIGHT:
00250                         uiSetRoundBox(9 + 16);
00251                         
00252                         uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
00253                         glColor4ub(0, 0, 0, 255);
00254                         uiRoundRect((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
00255                         break;
00256                 case AE_RIGHT_TO_TOPLEFT:
00257                         uiSetRoundBox(6 + 16);
00258                         
00259                         uiDrawBoxShade(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f);
00260                         glColor4ub(0, 0, 0, 255);
00261                         uiRoundRect((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f);
00262                         break;
00263         }
00264         
00265         glDisable(GL_BLEND);
00266 }
00267 
00268 static void region_draw_azone_tria(AZone *az)
00269 {
00270         extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
00271         
00272         glEnable(GL_BLEND);
00273         //UI_GetThemeColor3fv(TH_HEADER, col);
00274         glColor4f(0.0f, 0.0f, 0.0f, 0.35f);
00275         
00276         /* add code to draw region hidden as 'too small' */
00277         switch(az->edge) {
00278                 case AE_TOP_TO_BOTTOMRIGHT:
00279                         ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y1, (float)(az->x1+az->x2)/2, (float)az->y2);
00280                         break;
00281                         
00282                 case AE_BOTTOM_TO_TOPLEFT:
00283                         ui_draw_anti_tria((float)az->x1, (float)az->y2, (float)az->x2, (float)az->y2, (float)(az->x1+az->x2)/2, (float)az->y1);
00284                         break;
00285 
00286                 case AE_LEFT_TO_TOPRIGHT:
00287                         ui_draw_anti_tria((float)az->x2, (float)az->y1, (float)az->x2, (float)az->y2, (float)az->x1, (float)(az->y1+az->y2)/2);
00288                         break;
00289                         
00290                 case AE_RIGHT_TO_TOPLEFT:
00291                         ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x1, (float)az->y2, (float)az->x2, (float)(az->y1+az->y2)/2);
00292                         break;
00293                         
00294         }
00295         
00296         glDisable(GL_BLEND);
00297 }
00298 
00299 /* only exported for WM */
00300 void ED_area_overdraw(bContext *C)
00301 {
00302         wmWindow *win= CTX_wm_window(C);
00303         bScreen *screen= CTX_wm_screen(C);
00304         ScrArea *sa;
00305         
00306         /* Draw AZones, in screenspace */
00307         wmSubWindowSet(win, screen->mainwin);
00308 
00309         glEnable( GL_BLEND );
00310         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
00311         
00312         for(sa= screen->areabase.first; sa; sa= sa->next) {
00313                 AZone *az;
00314                 for(az= sa->actionzones.first; az; az= az->next) {
00315                         if(az->do_draw) {
00316                                 if(az->type==AZONE_AREA) {
00317                                         area_draw_azone(az->x1, az->y1, az->x2, az->y2);
00318                                 } else if(az->type==AZONE_REGION) {
00319                                         
00320                                         if(az->ar) {
00321                                                 /* only display tab or icons when the region is hidden */
00322                                                 if (az->ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
00323                                         
00324                                                         if(G.rt==2)
00325                                                                 region_draw_azone_tria(az);
00326                                                         else if(G.rt==1)
00327                                                                 region_draw_azone_tab(az);
00328                                                         else
00329                                                                 region_draw_azone_icon(az);
00330                                                 }
00331                                         }
00332                                 }
00333                                 
00334                                 az->do_draw= 0;
00335                         }
00336                 }
00337         }       
00338         glDisable( GL_BLEND );
00339         
00340 }
00341 
00342 /* get scissor rect, checking overlapping regions */
00343 void region_scissor_winrct(ARegion *ar, rcti *winrct)
00344 {
00345         *winrct= ar->winrct;
00346         
00347         if(ELEM(ar->alignment, RGN_OVERLAP_LEFT, RGN_OVERLAP_RIGHT))
00348                 return;
00349 
00350         while(ar->prev) {
00351                 ar= ar->prev;
00352                 
00353                 if(BLI_isect_rcti(winrct, &ar->winrct, NULL)) {
00354                         if(ar->flag & RGN_FLAG_HIDDEN);
00355                         else if(ar->alignment & RGN_SPLIT_PREV);
00356                         else if(ar->alignment==RGN_OVERLAP_LEFT) {
00357                                 winrct->xmin= ar->winrct.xmax + 1;
00358                         }
00359                         else if(ar->alignment==RGN_OVERLAP_RIGHT) {
00360                                 winrct->xmax= ar->winrct.xmin - 1;
00361                         }
00362                         else break;
00363                 }
00364         }
00365 }
00366 
00367 /* only exported for WM */
00368 /* makes region ready for drawing, sets pixelspace */
00369 void ED_region_set(const bContext *C, ARegion *ar)
00370 {
00371         wmWindow *win= CTX_wm_window(C);
00372         ScrArea *sa= CTX_wm_area(C);
00373         rcti winrct;
00374         
00375         /* checks other overlapping regions */
00376         region_scissor_winrct(ar, &winrct);
00377         
00378         ar->drawrct= winrct;
00379         
00380         /* note; this sets state, so we can use wmOrtho and friends */
00381         wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
00382         
00383         UI_SetTheme(sa?sa->spacetype:0, ar->type?ar->type->regionid:0);
00384         
00385         ED_region_pixelspace(ar);
00386 }
00387 
00388 
00389 /* only exported for WM */
00390 void ED_region_do_draw(bContext *C, ARegion *ar)
00391 {
00392         wmWindow *win= CTX_wm_window(C);
00393         ScrArea *sa= CTX_wm_area(C);
00394         ARegionType *at= ar->type;
00395         rcti winrct;
00396         
00397         /* see BKE_spacedata_draw_locks() */
00398         if(at->do_lock)
00399                 return;
00400         
00401         /* checks other overlapping regions */
00402         region_scissor_winrct(ar, &winrct);
00403         
00404         /* if no partial draw rect set, full rect */
00405         if(ar->drawrct.xmin == ar->drawrct.xmax)
00406                 ar->drawrct= winrct;
00407         else {
00408                 /* extra clip for safety */
00409                 ar->drawrct.xmin= MAX2(winrct.xmin, ar->drawrct.xmin);
00410                 ar->drawrct.ymin= MAX2(winrct.ymin, ar->drawrct.ymin);
00411                 ar->drawrct.xmax= MIN2(winrct.xmax, ar->drawrct.xmax);
00412                 ar->drawrct.ymax= MIN2(winrct.ymax, ar->drawrct.ymax);
00413         }
00414         
00415         /* note; this sets state, so we can use wmOrtho and friends */
00416         wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
00417         
00418         UI_SetTheme(sa?sa->spacetype:0, ar->type?ar->type->regionid:0);
00419         
00420         /* optional header info instead? */
00421         if(ar->headerstr) {
00422                 UI_ThemeClearColor(TH_HEADER);
00423                 glClear(GL_COLOR_BUFFER_BIT);
00424                 
00425                 UI_ThemeColor(TH_TEXT);
00426                 BLF_draw_default(20, 8, 0.0f, ar->headerstr, 65535); /* XXX, use real length */
00427         }
00428         else if(at->draw) {
00429                 at->draw(C, ar);
00430         }
00431 
00432         ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_PIXEL);
00433         
00434         uiFreeInactiveBlocks(C, &ar->uiblocks);
00435         
00436         if(sa)
00437                 region_draw_emboss(ar, &winrct);
00438         
00439         /* XXX test: add convention to end regions always in pixel space, for drawing of borders/gestures etc */
00440         ED_region_pixelspace(ar);
00441         
00442         ar->do_draw= 0;
00443         memset(&ar->drawrct, 0, sizeof(ar->drawrct));
00444 }
00445 
00446 /* **********************************
00447    maybe silly, but let's try for now
00448    to keep these tags protected
00449    ********************************** */
00450 
00451 void ED_region_tag_redraw(ARegion *ar)
00452 {
00453         if(ar) {
00454                 /* zero region means full region redraw */
00455                 ar->do_draw= RGN_DRAW;
00456                 memset(&ar->drawrct, 0, sizeof(ar->drawrct));
00457         }
00458 }
00459 
00460 void ED_region_tag_redraw_overlay(ARegion *ar)
00461 {
00462         if(ar)
00463                 ar->do_draw_overlay= RGN_DRAW;
00464 }
00465 
00466 void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct)
00467 {
00468         if(ar) {
00469                 if(!ar->do_draw) {
00470                         /* no redraw set yet, set partial region */
00471                         ar->do_draw= RGN_DRAW_PARTIAL;
00472                         ar->drawrct= *rct;
00473                 }
00474                 else if(ar->drawrct.xmin != ar->drawrct.xmax) {
00475                         /* partial redraw already set, expand region */
00476                         ar->drawrct.xmin= MIN2(ar->drawrct.xmin, rct->xmin);
00477                         ar->drawrct.ymin= MIN2(ar->drawrct.ymin, rct->ymin);
00478                         ar->drawrct.xmax= MAX2(ar->drawrct.xmax, rct->xmax);
00479                         ar->drawrct.ymax= MAX2(ar->drawrct.ymax, rct->ymax);
00480                 }
00481         }
00482 }
00483 
00484 void ED_area_tag_redraw(ScrArea *sa)
00485 {
00486         ARegion *ar;
00487         
00488         if(sa)
00489                 for(ar= sa->regionbase.first; ar; ar= ar->next)
00490                         ED_region_tag_redraw(ar);
00491 }
00492 
00493 void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
00494 {
00495         ARegion *ar;
00496         
00497         if(sa) {
00498                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
00499                         if(ar->regiontype == regiontype) {
00500                                 ED_region_tag_redraw(ar);
00501                         }
00502                 }
00503         }
00504 }
00505 
00506 void ED_area_tag_refresh(ScrArea *sa)
00507 {
00508         if(sa)
00509                 sa->do_refresh= 1;
00510 }
00511 
00512 /* *************************************************************** */
00513 
00514 /* use NULL to disable it */
00515 void ED_area_headerprint(ScrArea *sa, const char *str)
00516 {
00517         ARegion *ar;
00518 
00519         /* happens when running transform operators in backround mode */
00520         if(sa == NULL)
00521                 return;
00522 
00523         for(ar= sa->regionbase.first; ar; ar= ar->next) {
00524                 if(ar->regiontype==RGN_TYPE_HEADER) {
00525                         if(str) {
00526                                 if(ar->headerstr==NULL)
00527                                         ar->headerstr= MEM_mallocN(256, "headerprint");
00528                                 BLI_strncpy(ar->headerstr, str, 256);
00529                         }
00530                         else if(ar->headerstr) {
00531                                 MEM_freeN(ar->headerstr);
00532                                 ar->headerstr= NULL;
00533                         }
00534                         ED_region_tag_redraw(ar);
00535                 }
00536         }
00537 }
00538 
00539 /* ************************************************************ */
00540 
00541 
00542 static void area_azone_initialize(ScrArea *sa) 
00543 {
00544         AZone *az;
00545         
00546         /* reinitalize entirely, regions add azones too */
00547         BLI_freelistN(&sa->actionzones);
00548         
00549         /* set area action zones */
00550         az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
00551         BLI_addtail(&(sa->actionzones), az);
00552         az->type= AZONE_AREA;
00553         az->x1= sa->totrct.xmin;
00554         az->y1= sa->totrct.ymin;
00555         az->x2= sa->totrct.xmin + AZONESPOT;
00556         az->y2= sa->totrct.ymin + AZONESPOT;
00557         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00558         
00559         az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
00560         BLI_addtail(&(sa->actionzones), az);
00561         az->type= AZONE_AREA;
00562         az->x1= sa->totrct.xmax+1;
00563         az->y1= sa->totrct.ymax+1;
00564         az->x2= sa->totrct.xmax-AZONESPOT;
00565         az->y2= sa->totrct.ymax-AZONESPOT;
00566         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00567 }
00568 
00569 #define AZONEPAD_EDGE   4
00570 #define AZONEPAD_ICON   9
00571 static void region_azone_edge(AZone *az, ARegion *ar)
00572 {
00573         switch(az->edge) {
00574                 case AE_TOP_TO_BOTTOMRIGHT:
00575                         az->x1= ar->winrct.xmin;
00576                         az->y1= ar->winrct.ymax - AZONEPAD_EDGE;
00577                         az->x2= ar->winrct.xmax;
00578                         az->y2= ar->winrct.ymax;
00579                         break;
00580                 case AE_BOTTOM_TO_TOPLEFT:
00581                         az->x1= ar->winrct.xmin;
00582                         az->y1= ar->winrct.ymin + AZONEPAD_EDGE;
00583                         az->x2= ar->winrct.xmax;
00584                         az->y2= ar->winrct.ymin;
00585                         break;
00586                 case AE_LEFT_TO_TOPRIGHT:
00587                         az->x1= ar->winrct.xmin;
00588                         az->y1= ar->winrct.ymin;
00589                         az->x2= ar->winrct.xmin + AZONEPAD_EDGE;
00590                         az->y2= ar->winrct.ymax;
00591                         break;
00592                 case AE_RIGHT_TO_TOPLEFT:
00593                         az->x1= ar->winrct.xmax;
00594                         az->y1= ar->winrct.ymin;
00595                         az->x2= ar->winrct.xmax - AZONEPAD_EDGE;
00596                         az->y2= ar->winrct.ymax;
00597                         break;
00598         }
00599 
00600         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00601 }
00602 
00603 static void region_azone_icon(ScrArea *sa, AZone *az, ARegion *ar)
00604 {
00605         AZone *azt;
00606         int tot=0;
00607         
00608         /* count how many actionzones with along same edge are available.
00609            This allows for adding more action zones in the future without
00610            having to worry about correct offset */
00611         for(azt= sa->actionzones.first; azt; azt= azt->next) {
00612                 if(azt->edge == az->edge) tot++;
00613         }
00614         
00615         switch(az->edge) {
00616                 case AE_TOP_TO_BOTTOMRIGHT:
00617                         az->x1= ar->winrct.xmax - tot*2*AZONEPAD_ICON;
00618                         az->y1= ar->winrct.ymax + AZONEPAD_ICON;
00619                         az->x2= ar->winrct.xmax - tot*AZONEPAD_ICON;
00620                         az->y2= ar->winrct.ymax + 2*AZONEPAD_ICON;
00621                         break;
00622                 case AE_BOTTOM_TO_TOPLEFT:
00623                         az->x1= ar->winrct.xmin + AZONEPAD_ICON;
00624                         az->y1= ar->winrct.ymin - 2*AZONEPAD_ICON;
00625                         az->x2= ar->winrct.xmin + 2*AZONEPAD_ICON;
00626                         az->y2= ar->winrct.ymin - AZONEPAD_ICON;
00627                         break;
00628                 case AE_LEFT_TO_TOPRIGHT:
00629                         az->x1= ar->winrct.xmin - 2*AZONEPAD_ICON;
00630                         az->y1= ar->winrct.ymax - tot*2*AZONEPAD_ICON;
00631                         az->x2= ar->winrct.xmin - AZONEPAD_ICON;
00632                         az->y2= ar->winrct.ymax - tot*AZONEPAD_ICON;
00633                         break;
00634                 case AE_RIGHT_TO_TOPLEFT:
00635                         az->x1= ar->winrct.xmax + AZONEPAD_ICON;
00636                         az->y1= ar->winrct.ymax - tot*2*AZONEPAD_ICON;
00637                         az->x2= ar->winrct.xmax + 2*AZONEPAD_ICON;
00638                         az->y2= ar->winrct.ymax - tot*AZONEPAD_ICON;
00639                         break;
00640         }
00641 
00642         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00643         
00644         /* if more azones on 1 spot, set offset */
00645         for(azt= sa->actionzones.first; azt; azt= azt->next) {
00646                 if(az!=azt) {
00647                         if( ABS(az->x1-azt->x1) < 2 && ABS(az->y1-azt->y1) < 2) {
00648                                 if(az->edge==AE_TOP_TO_BOTTOMRIGHT || az->edge==AE_BOTTOM_TO_TOPLEFT) {
00649                                         az->x1+= AZONESPOT;
00650                                         az->x2+= AZONESPOT;
00651                                 }
00652                                 else{
00653                                         az->y1-= AZONESPOT;
00654                                         az->y2-= AZONESPOT;
00655                                 }
00656                                 BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00657                         }
00658                 }
00659         }
00660 }
00661 
00662 #define AZONEPAD_TABW   18
00663 #define AZONEPAD_TABH   7
00664 
00665 /* region already made zero sized, in shape of edge */
00666 static void region_azone_tab(ScrArea *sa, AZone *az, ARegion *ar)
00667 {
00668         AZone *azt;
00669         int tot= 0, add;
00670         
00671         for(azt= sa->actionzones.first; azt; azt= azt->next) {
00672                 if(azt->edge == az->edge) tot++;
00673         }
00674         
00675         switch(az->edge) {
00676                 case AE_TOP_TO_BOTTOMRIGHT:
00677                         if(ar->winrct.ymax == sa->totrct.ymin) add= 1; else add= 0;
00678                         az->x1= ar->winrct.xmax - 2*AZONEPAD_TABW;
00679                         az->y1= ar->winrct.ymax - add;
00680                         az->x2= ar->winrct.xmax - AZONEPAD_TABW;
00681                         az->y2= ar->winrct.ymax - add + AZONEPAD_TABH;
00682                         break;
00683                 case AE_BOTTOM_TO_TOPLEFT:
00684                         az->x1= ar->winrct.xmin + AZONEPAD_TABW;
00685                         az->y1= ar->winrct.ymin - AZONEPAD_TABH;
00686                         az->x2= ar->winrct.xmin + 2*AZONEPAD_TABW;
00687                         az->y2= ar->winrct.ymin;
00688                         break;
00689                 case AE_LEFT_TO_TOPRIGHT:
00690                         az->x1= ar->winrct.xmin + 1 - AZONEPAD_TABH;
00691                         az->y1= ar->winrct.ymax - 2*AZONEPAD_TABW;
00692                         az->x2= ar->winrct.xmin + 1;
00693                         az->y2= ar->winrct.ymax - AZONEPAD_TABW;
00694                         break;
00695                 case AE_RIGHT_TO_TOPLEFT:
00696                         az->x1= ar->winrct.xmax - 1;
00697                         az->y1= ar->winrct.ymax - 2*AZONEPAD_TABW;
00698                         az->x2= ar->winrct.xmax - 1 + AZONEPAD_TABH;
00699                         az->y2= ar->winrct.ymax - AZONEPAD_TABW;
00700                         break;
00701         }
00702         /* rect needed for mouse pointer test */
00703         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00704 }       
00705 
00706 #define AZONEPAD_TRIAW  16
00707 #define AZONEPAD_TRIAH  9
00708 
00709 
00710 /* region already made zero sized, in shape of edge */
00711 static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
00712 {
00713         AZone *azt;
00714         int tot= 0, add;
00715         
00716         for(azt= sa->actionzones.first; azt; azt= azt->next) {
00717                 if(azt->edge == az->edge) tot++;
00718         }
00719         
00720         switch(az->edge) {
00721                 case AE_TOP_TO_BOTTOMRIGHT:
00722                         if(ar->winrct.ymax == sa->totrct.ymin) add= 1; else add= 0;
00723                         az->x1= ar->winrct.xmax - 2*AZONEPAD_TRIAW;
00724                         az->y1= ar->winrct.ymax - add;
00725                         az->x2= ar->winrct.xmax - AZONEPAD_TRIAW;
00726                         az->y2= ar->winrct.ymax - add + AZONEPAD_TRIAH;
00727                         break;
00728                         case AE_BOTTOM_TO_TOPLEFT:
00729                         az->x1= ar->winrct.xmin + AZONEPAD_TRIAW;
00730                         az->y1= ar->winrct.ymin - AZONEPAD_TRIAH;
00731                         az->x2= ar->winrct.xmin + 2*AZONEPAD_TRIAW;
00732                         az->y2= ar->winrct.ymin;
00733                         break;
00734                         case AE_LEFT_TO_TOPRIGHT:
00735                         az->x1= ar->winrct.xmin + 1 - AZONEPAD_TRIAH;
00736                         az->y1= ar->winrct.ymax - 2*AZONEPAD_TRIAW;
00737                         az->x2= ar->winrct.xmin + 1;
00738                         az->y2= ar->winrct.ymax - AZONEPAD_TRIAW;
00739                         break;
00740                         case AE_RIGHT_TO_TOPLEFT:
00741                         az->x1= ar->winrct.xmax - 1;
00742                         az->y1= ar->winrct.ymax - 2*AZONEPAD_TRIAW;
00743                         az->x2= ar->winrct.xmax - 1 + AZONEPAD_TRIAH;
00744                         az->y2= ar->winrct.ymax - AZONEPAD_TRIAW;
00745                         break;
00746         }
00747         /* rect needed for mouse pointer test */
00748         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
00749 }       
00750 
00751 
00752 static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge) 
00753 {
00754         AZone *az;
00755         
00756         az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
00757         BLI_addtail(&(sa->actionzones), az);
00758         az->type= AZONE_REGION;
00759         az->ar= ar;
00760         az->edge= edge;
00761         
00762         if (ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
00763                 if(G.rt==2)
00764                         region_azone_tria(sa, az, ar);
00765                 else if(G.rt==1)
00766                         region_azone_tab(sa, az, ar);
00767                 else
00768                         region_azone_icon(sa, az, ar);
00769         } else {
00770                 region_azone_edge(az, ar);
00771         }
00772         
00773 }
00774 
00775 
00776 /* *************************************************************** */
00777 
00778 static void region_azone_add(ScrArea *sa, ARegion *ar, int alignment)
00779 {
00780          /* edge code (t b l r) is along which area edge azone will be drawn */
00781         
00782         if(alignment==RGN_ALIGN_TOP)
00783                 region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT);
00784         else if(alignment==RGN_ALIGN_BOTTOM)
00785                 region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT);
00786         else if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT))
00787                 region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT);
00788         else if(ELEM(alignment, RGN_ALIGN_LEFT, RGN_OVERLAP_LEFT))
00789                 region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT);
00790 }
00791 
00792 /* dir is direction to check, not the splitting edge direction! */
00793 static int rct_fits(rcti *rect, char dir, int size)
00794 {
00795         if(dir=='h') {
00796                 return rect->xmax-rect->xmin - size;
00797         }
00798         else { // 'v'
00799                 return rect->ymax-rect->ymin - size;
00800         }
00801 }
00802 
00803 static void region_rect_recursive(ScrArea *sa, ARegion *ar, rcti *remainder, int quad)
00804 {
00805         rcti *remainder_prev= remainder;
00806         int prefsizex, prefsizey;
00807         int alignment;
00808         
00809         if(ar==NULL)
00810                 return;
00811         
00812         /* no returns in function, winrct gets set in the end again */
00813         BLI_init_rcti(&ar->winrct, 0, 0, 0, 0);
00814         
00815         /* for test; allow split of previously defined region */
00816         if(ar->alignment & RGN_SPLIT_PREV)
00817                 if(ar->prev)
00818                         remainder= &ar->prev->winrct;
00819         
00820         alignment = ar->alignment & ~RGN_SPLIT_PREV;
00821         
00822         /* clear state flags first */
00823         ar->flag &= ~RGN_FLAG_TOO_SMALL;
00824         /* user errors */
00825         if(ar->next==NULL && alignment!=RGN_ALIGN_QSPLIT)
00826                 alignment= RGN_ALIGN_NONE;
00827         
00828         /* prefsize, for header we stick to exception */
00829         prefsizex= ar->sizex?ar->sizex:ar->type->prefsizex;
00830         if(ar->regiontype==RGN_TYPE_HEADER)
00831                 prefsizey= ar->type->prefsizey;
00832         else
00833                 prefsizey= ar->sizey?ar->sizey:ar->type->prefsizey;
00834         
00835         /* hidden is user flag */
00836         if(ar->flag & RGN_FLAG_HIDDEN);
00837         /* XXX floating area region, not handled yet here */
00838         else if(alignment == RGN_ALIGN_FLOAT);
00839         /* remainder is too small for any usage */
00840         else if( rct_fits(remainder, 'v', 1)<0 || rct_fits(remainder, 'h', 1) < 0 ) {
00841                 ar->flag |= RGN_FLAG_TOO_SMALL;
00842         }
00843         else if(alignment==RGN_ALIGN_NONE) {
00844                 /* typically last region */
00845                 ar->winrct= *remainder;
00846                 BLI_init_rcti(remainder, 0, 0, 0, 0);
00847         }
00848         else if(alignment==RGN_ALIGN_TOP || alignment==RGN_ALIGN_BOTTOM) {
00849                 
00850                 if( rct_fits(remainder, 'v', prefsizey) < 0 ) {
00851                         ar->flag |= RGN_FLAG_TOO_SMALL;
00852                 }
00853                 else {
00854                         int fac= rct_fits(remainder, 'v', prefsizey);
00855 
00856                         if(fac < 0 )
00857                                 prefsizey += fac;
00858                         
00859                         ar->winrct= *remainder;
00860                         
00861                         if(alignment==RGN_ALIGN_TOP) {
00862                                 ar->winrct.ymin= ar->winrct.ymax - prefsizey + 1;
00863                                 remainder->ymax= ar->winrct.ymin - 1;
00864                         }
00865                         else {
00866                                 ar->winrct.ymax= ar->winrct.ymin + prefsizey - 1;
00867                                 remainder->ymin= ar->winrct.ymax + 1;
00868                         }
00869                 }
00870         }
00871         else if( ELEM4(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT, RGN_OVERLAP_LEFT, RGN_OVERLAP_RIGHT)) {
00872                 
00873                 if( rct_fits(remainder, 'h', prefsizex) < 0 ) {
00874                         ar->flag |= RGN_FLAG_TOO_SMALL;
00875                 }
00876                 else {
00877                         int fac= rct_fits(remainder, 'h', prefsizex);
00878                         
00879                         if(fac < 0 )
00880                                 prefsizex += fac;
00881                         
00882                         ar->winrct= *remainder;
00883                         
00884                         if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT)) {
00885                                 ar->winrct.xmin= ar->winrct.xmax - prefsizex + 1;
00886                                 if(alignment==RGN_ALIGN_RIGHT)
00887                                         remainder->xmax= ar->winrct.xmin - 1;
00888                         }
00889                         else {
00890                                 ar->winrct.xmax= ar->winrct.xmin + prefsizex - 1;
00891                                 if(alignment==RGN_ALIGN_LEFT)
00892                                         remainder->xmin= ar->winrct.xmax + 1;
00893                         }
00894                 }
00895         }
00896         else if(alignment==RGN_ALIGN_VSPLIT || alignment==RGN_ALIGN_HSPLIT) {
00897                 /* percentage subdiv*/
00898                 ar->winrct= *remainder;
00899                 
00900                 if(alignment==RGN_ALIGN_HSPLIT) {
00901                         if( rct_fits(remainder, 'h', prefsizex) > 4) {
00902                                 ar->winrct.xmax= (remainder->xmin+remainder->xmax)/2;
00903                                 remainder->xmin= ar->winrct.xmax+1;
00904                         }
00905                         else {
00906                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
00907                         }
00908                 }
00909                 else {
00910                         if( rct_fits(remainder, 'v', prefsizey) > 4) {
00911                                 ar->winrct.ymax= (remainder->ymin+remainder->ymax)/2;
00912                                 remainder->ymin= ar->winrct.ymax+1;
00913                         }
00914                         else {
00915                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
00916                         }
00917                 }
00918         }
00919         else if(alignment==RGN_ALIGN_QSPLIT) {
00920                 ar->winrct= *remainder;
00921                 
00922                 /* test if there's still 4 regions left */
00923                 if(quad==0) {
00924                         ARegion *artest= ar->next;
00925                         int count= 1;
00926                         
00927                         while(artest) {
00928                                 artest->alignment= RGN_ALIGN_QSPLIT;
00929                                 artest= artest->next;
00930                                 count++;
00931                         }
00932                         
00933                         if(count!=4) {
00934                                 /* let's stop adding regions */
00935                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
00936                                 if (G.f & G_DEBUG)
00937                                         printf("region quadsplit failed\n");
00938                         }
00939                         else quad= 1;
00940                 }
00941                 if(quad) {
00942                         if(quad==1) { /* left bottom */
00943                                 ar->winrct.xmax = (remainder->xmin + remainder->xmax)/2;
00944                                 ar->winrct.ymax = (remainder->ymin + remainder->ymax)/2;
00945                         }
00946                         else if(quad==2) { /* left top */
00947                                 ar->winrct.xmax = (remainder->xmin + remainder->xmax)/2;
00948                                 ar->winrct.ymin = 1 + (remainder->ymin + remainder->ymax)/2;
00949                         }
00950                         else if(quad==3) { /* right bottom */
00951                                 ar->winrct.xmin = 1 + (remainder->xmin + remainder->xmax)/2;
00952                                 ar->winrct.ymax = (remainder->ymin + remainder->ymax)/2;
00953                         }
00954                         else {  /* right top */
00955                                 ar->winrct.xmin = 1 + (remainder->xmin + remainder->xmax)/2;
00956                                 ar->winrct.ymin = 1 + (remainder->ymin + remainder->ymax)/2;
00957                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
00958                         }
00959 
00960                         quad++;
00961                 }
00962         }
00963         
00964         /* for speedup */
00965         ar->winx= ar->winrct.xmax - ar->winrct.xmin + 1;
00966         ar->winy= ar->winrct.ymax - ar->winrct.ymin + 1;
00967         
00968         /* set winrect for azones */
00969         if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
00970                 ar->winrct= *remainder;
00971                 
00972                 if(alignment==RGN_ALIGN_TOP)
00973                         ar->winrct.ymin= ar->winrct.ymax;
00974                 else if(alignment==RGN_ALIGN_BOTTOM)
00975                         ar->winrct.ymax= ar->winrct.ymin;
00976                 else if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT))
00977                         ar->winrct.xmin= ar->winrct.xmax;
00978                 else if(ELEM(alignment, RGN_ALIGN_LEFT, RGN_OVERLAP_LEFT))
00979                         ar->winrct.xmax= ar->winrct.xmin;
00980                 else /* prevent winrct to be valid */
00981                         ar->winrct.xmax= ar->winrct.xmin;
00982         }
00983 
00984         /* restore prev-split exception */
00985         if(ar->alignment & RGN_SPLIT_PREV) {
00986                 if(ar->prev) {
00987                         remainder= remainder_prev;
00988                         ar->prev->winx= ar->prev->winrct.xmax - ar->prev->winrct.xmin + 1;
00989                         ar->prev->winy= ar->prev->winrct.ymax - ar->prev->winrct.ymin + 1;
00990                 }
00991         }
00992         
00993         /* in end, add azones, where appropriate */
00994         if(ar->regiontype == RGN_TYPE_HEADER && ar->winy + 6 > sa->winy) {
00995                 /* The logic for this is: when the header takes up the full area,
00996                  * disallow hiding it to view the main window.
00997                  *
00998                  * Without this, you can drag down the file selectors header and hide it
00999                  * by accident very easily (highly annoying!), the value 6 is arbitrary
01000                  * but accounts for small common rounding problems when scaling the UI,
01001                  * must be minimum '4' */
01002         }
01003         else {
01004                 region_azone_add(sa, ar, alignment);
01005         }
01006 
01007         region_rect_recursive(sa, ar->next, remainder, quad);
01008 }
01009 
01010 static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
01011 {
01012         short rt= 0; // CLAMPIS(G.rt, 0, 16);
01013 
01014         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1+rt;
01015         else sa->totrct.xmin= sa->v1->vec.x;
01016         if(sa->v4->vec.x<sizex-1) sa->totrct.xmax= sa->v4->vec.x-1-rt;
01017         else sa->totrct.xmax= sa->v4->vec.x;
01018         
01019         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1+rt;
01020         else sa->totrct.ymin= sa->v1->vec.y;
01021         if(sa->v2->vec.y<sizey-1) sa->totrct.ymax= sa->v2->vec.y-1-rt;
01022         else sa->totrct.ymax= sa->v2->vec.y;
01023         
01024         /* for speedup */
01025         sa->winx= sa->totrct.xmax-sa->totrct.xmin+1;
01026         sa->winy= sa->totrct.ymax-sa->totrct.ymin+1;
01027 }
01028 
01029 
01030 /* used for area initialize below */
01031 static void region_subwindow(wmWindow *win, ARegion *ar)
01032 {
01033         if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
01034                 if(ar->swinid)
01035                         wm_subwindow_close(win, ar->swinid);
01036                 ar->swinid= 0;
01037         }
01038         else if(ar->swinid==0)
01039                 ar->swinid= wm_subwindow_open(win, &ar->winrct);
01040         else 
01041                 wm_subwindow_position(win, ar->swinid, &ar->winrct);
01042 }
01043 
01044 static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag)
01045 {
01046         /* note, add-handler checks if it already exists */
01047         
01048         // XXX it would be good to have boundbox checks for some of these...
01049         if(flag & ED_KEYMAP_UI) {
01050                 /* user interface widgets */
01051                 UI_add_region_handlers(handlers);
01052         }
01053         if(flag & ED_KEYMAP_VIEW2D) {
01054                 /* 2d-viewport handling+manipulation */
01055                 wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "View2D", 0, 0);
01056                 WM_event_add_keymap_handler(handlers, keymap);
01057         }
01058         if(flag & ED_KEYMAP_MARKERS) {
01059                 /* time-markers */
01060                 wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Markers", 0, 0);
01061                 
01062                 /* time space only has this keymap, the others get a boundbox restricted map */
01063                 if(sa->spacetype!=SPACE_TIME) {
01064                         ARegion *ar;
01065                         static rcti rect= {0, 10000, 0, 30};    /* same local check for all areas */
01066                         ar= BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
01067                         if(ar) {
01068                                 WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
01069                         }
01070                 }
01071                 else
01072                         WM_event_add_keymap_handler(handlers, keymap);
01073         }
01074         if(flag & ED_KEYMAP_ANIMATION) {
01075                 /* frame changing and timeline operators (for time spaces) */
01076                 wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Animation", 0, 0);
01077                 WM_event_add_keymap_handler(handlers, keymap);
01078         }
01079         if(flag & ED_KEYMAP_FRAMES) {
01080                 /* frame changing/jumping (for all spaces) */
01081                 wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Frames", 0, 0);
01082                 WM_event_add_keymap_handler(handlers, keymap);
01083         }
01084         if(flag & ED_KEYMAP_GPENCIL) {
01085                 /* grease pencil */
01086                 wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
01087                 WM_event_add_keymap_handler(handlers, keymap);
01088         }
01089         if(flag & ED_KEYMAP_HEADER) {
01090                 /* standard keymap for headers regions */
01091                 wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Header", 0, 0);
01092                 WM_event_add_keymap_handler(handlers, keymap);
01093         }
01094 }
01095 
01096 
01097 /* called in screen_refresh, or screens_init, also area size changes */
01098 void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
01099 {
01100         ARegion *ar;
01101         rcti rect;
01102         
01103         /* set typedefinitions */
01104         sa->type= BKE_spacetype_from_id(sa->spacetype);
01105         
01106         if(sa->type==NULL) {
01107                 sa->butspacetype= sa->spacetype= SPACE_VIEW3D;
01108                 sa->type= BKE_spacetype_from_id(sa->spacetype);
01109         }
01110         
01111         for(ar= sa->regionbase.first; ar; ar= ar->next)
01112                 ar->type= BKE_regiontype_from_id(sa->type, ar->regiontype);
01113         
01114         /* area sizes */
01115         area_calc_totrct(sa, win->sizex, win->sizey);
01116         
01117         /* clear all azones, add the area triange widgets */
01118         area_azone_initialize(sa);
01119 
01120         /* region rect sizes */
01121         rect= sa->totrct;
01122         region_rect_recursive(sa, sa->regionbase.first, &rect, 0);
01123         
01124         /* default area handlers */
01125         ed_default_handlers(wm, sa, &sa->handlers, sa->type->keymapflag);
01126         /* checks spacedata, adds own handlers */
01127         if(sa->type->init)
01128                 sa->type->init(wm, sa);
01129         
01130         /* region windows, default and own handlers */
01131         for(ar= sa->regionbase.first; ar; ar= ar->next) {
01132                 region_subwindow(win, ar);
01133                 
01134                 if(ar->swinid) {
01135                         /* default region handlers */
01136                         ed_default_handlers(wm, sa, &ar->handlers, ar->type->keymapflag);
01137                         /* own handlers */
01138                         if(ar->type->init)
01139                                 ar->type->init(wm, ar);
01140                 }
01141                 else {
01142                         /* prevent uiblocks to run */
01143                         uiFreeBlocks(NULL, &ar->uiblocks);      
01144                 }
01145                 
01146                 /* rechecks 2d matrix for header on dpi changing, do not do for other regions, it resets view && blocks view2d operator polls (ton) */
01147                 if(ar->regiontype==RGN_TYPE_HEADER)
01148                         ar->v2d.flag &= ~V2D_IS_INITIALISED;
01149         }
01150 }
01151 
01152 /* externally called for floating regions like menus */
01153 void ED_region_init(bContext *C, ARegion *ar)
01154 {
01155 //      ARegionType *at= ar->type;
01156         
01157         /* refresh can be called before window opened */
01158         region_subwindow(CTX_wm_window(C), ar);
01159         
01160         ar->winx= ar->winrct.xmax - ar->winrct.xmin + 1;
01161         ar->winy= ar->winrct.ymax - ar->winrct.ymin + 1;
01162         
01163         /* UI convention */
01164         wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f);
01165         glLoadIdentity();
01166 }
01167 
01168 void ED_region_toggle_hidden(bContext *C, ARegion *ar)
01169 {
01170         ScrArea *sa= CTX_wm_area(C);
01171 
01172         ar->flag ^= RGN_FLAG_HIDDEN;
01173 
01174         if(ar->flag & RGN_FLAG_HIDDEN)
01175                 WM_event_remove_handlers(C, &ar->handlers);
01176 
01177         ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
01178         ED_area_tag_redraw(sa);
01179 }
01180 
01181 /* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
01182 /* area vertices were set */
01183 void area_copy_data(ScrArea *sa1, ScrArea *sa2, int swap_space)
01184 {
01185         SpaceType *st;
01186         ARegion *ar;
01187         int spacetype= sa1->spacetype;
01188         
01189         sa1->headertype= sa2->headertype;
01190         sa1->spacetype= sa2->spacetype;
01191         sa1->butspacetype= sa2->butspacetype;
01192         
01193         if(swap_space == 1) {
01194                 SWAP(ListBase, sa1->spacedata, sa2->spacedata);
01195                 /* exception: ensure preview is reset */
01196 //              if(sa1->spacetype==SPACE_VIEW3D)
01197 // XXX                  BIF_view3d_previewrender_free(sa1->spacedata.first);
01198         }
01199         else if (swap_space == 2) {
01200                 BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
01201         }
01202         else {
01203                 BKE_spacedata_freelist(&sa1->spacedata);
01204                 BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
01205         }
01206         
01207         /* Note; SPACE_EMPTY is possible on new screens */
01208         
01209         /* regions */
01210         if(swap_space == 1) {
01211                 SWAP(ListBase, sa1->regionbase, sa2->regionbase);
01212         }
01213         else {
01214                 if(swap_space<2) {
01215                         st= BKE_spacetype_from_id(spacetype);
01216                         for(ar= sa1->regionbase.first; ar; ar= ar->next)
01217                                 BKE_area_region_free(st, ar);
01218                         BLI_freelistN(&sa1->regionbase);
01219                 }
01220                 
01221                 st= BKE_spacetype_from_id(sa2->spacetype);
01222                 for(ar= sa2->regionbase.first; ar; ar= ar->next) {
01223                         ARegion *newar= BKE_area_region_copy(st, ar);
01224                         BLI_addtail(&sa1->regionbase, newar);
01225                 }
01226         }
01227 }
01228 
01229 /* *********** Space switching code *********** */
01230 
01231 void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
01232 {
01233         ScrArea *tmp= MEM_callocN(sizeof(ScrArea), "addscrarea");
01234 
01235         ED_area_exit(C, sa1);
01236         ED_area_exit(C, sa2);
01237 
01238         area_copy_data(tmp, sa1, 2);
01239         area_copy_data(sa1, sa2, 0);
01240         area_copy_data(sa2, tmp, 0);
01241         ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa1);
01242         ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa2);
01243 
01244         BKE_screen_area_free(tmp);
01245         MEM_freeN(tmp);
01246 
01247         /* tell WM to refresh, cursor types etc */
01248         WM_event_add_mousemove(C);
01249         
01250         ED_area_tag_redraw(sa1);
01251         ED_area_tag_refresh(sa1);
01252         ED_area_tag_redraw(sa2);
01253         ED_area_tag_refresh(sa2);
01254 }
01255 
01256 void ED_area_newspace(bContext *C, ScrArea *sa, int type)
01257 {
01258         if(sa->spacetype != type) {
01259                 SpaceType *st;
01260                 SpaceLink *slold;
01261                 SpaceLink *sl;
01262 
01263                 ED_area_exit(C, sa);
01264 
01265                 st= BKE_spacetype_from_id(type);
01266                 slold= sa->spacedata.first;
01267 
01268                 sa->spacetype= type;
01269                 sa->butspacetype= type;
01270                 sa->type= st;
01271                 
01272                 /* check previously stored space */
01273                 for (sl= sa->spacedata.first; sl; sl= sl->next)
01274                         if(sl->spacetype==type)
01275                                 break;
01276                 
01277                 /* old spacedata... happened during work on 2.50, remove */
01278                 if(sl && sl->regionbase.first==NULL) {
01279                         st->free(sl);
01280                         BLI_freelinkN(&sa->spacedata, sl);
01281                         if(slold == sl) {
01282                                 slold= NULL;
01283                         }
01284                         sl= NULL;
01285                 }
01286                 
01287                 if (sl) {
01288                         
01289                         /* swap regions */
01290                         slold->regionbase= sa->regionbase;
01291                         sa->regionbase= sl->regionbase;
01292                         sl->regionbase.first= sl->regionbase.last= NULL;
01293                         
01294                         /* put in front of list */
01295                         BLI_remlink(&sa->spacedata, sl);
01296                         BLI_addhead(&sa->spacedata, sl);
01297                 } 
01298                 else {
01299                         /* new space */
01300                         if(st) {
01301                                 sl= st->new(C);
01302                                 BLI_addhead(&sa->spacedata, sl);
01303                                 
01304                                 /* swap regions */
01305                                 if(slold)
01306                                         slold->regionbase= sa->regionbase;
01307                                 sa->regionbase= sl->regionbase;
01308                                 sl->regionbase.first= sl->regionbase.last= NULL;
01309                         }
01310                 }
01311                 
01312                 ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
01313                 
01314                 /* tell WM to refresh, cursor types etc */
01315                 WM_event_add_mousemove(C);
01316                                 
01317                 /*send space change notifier*/
01318                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_CHANGED, sa);
01319                 
01320                 ED_area_tag_refresh(sa);
01321         }
01322         
01323         /* also redraw when re-used */
01324         ED_area_tag_redraw(sa);
01325 }
01326 
01327 void ED_area_prevspace(bContext *C, ScrArea *sa)
01328 {
01329         SpaceLink *sl = (sa) ? sa->spacedata.first : CTX_wm_space_data(C);
01330 
01331         if(sl->next) {
01332                 /* workaround for case of double prevspace, render window
01333                    with a file browser on top of it */
01334                 if(sl->next->spacetype == SPACE_FILE && sl->next->next)
01335                         ED_area_newspace(C, sa, sl->next->next->spacetype);
01336                 else
01337                         ED_area_newspace(C, sa, sl->next->spacetype);
01338         }
01339         else {
01340                 ED_area_newspace(C, sa, SPACE_INFO);
01341         }
01342         ED_area_tag_redraw(sa);
01343 
01344         /*send space change notifier*/
01345         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_CHANGED, sa);
01346 }
01347 
01348 static const char *editortype_pup(void)
01349 {
01350         return(
01351                    "Editor type:%t"
01352                    "|3D View %x1"
01353 
01354                    "|%l"
01355                    
01356                    "|Timeline %x15"
01357                    "|Graph Editor %x2"
01358                    "|DopeSheet %x12"
01359                    "|NLA Editor %x13"
01360                    
01361                    "|%l"
01362                    
01363                    "|UV/Image Editor %x6"
01364                    
01365                    "|Video Sequence Editor %x8"
01366                    "|Text Editor %x9" 
01367                    "|Node Editor %x16"
01368                    "|Logic Editor %x17"
01369                    
01370                    "|%l"
01371                    
01372                    "|Properties %x4"
01373                    "|Outliner %x3"
01374                    "|User Preferences %x19"
01375                    "|Info%x7"
01376                                    
01377                    "|%l"
01378                    
01379                    "|File Browser %x5"
01380                    
01381                    "|%l"
01382                    
01383                    "|Python Console %x18"
01384                    );
01385 }
01386 
01387 static void spacefunc(struct bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
01388 {
01389         ED_area_newspace(C, CTX_wm_area(C), CTX_wm_area(C)->butspacetype);
01390         ED_area_tag_redraw(CTX_wm_area(C));
01391 
01392         /*send space change notifier*/
01393         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_CHANGED, CTX_wm_area(C));
01394 }
01395 
01396 /* returns offset for next button in header */
01397 int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
01398 {
01399         ScrArea *sa= CTX_wm_area(C);
01400         uiBut *but;
01401         int xco= 8;
01402         
01403         but= uiDefIconTextButC(block, ICONTEXTROW, 0, ICON_VIEW3D, 
01404                                                    editortype_pup(), xco, yco, UI_UNIT_X+10, UI_UNIT_Y, 
01405                                                    &(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0, 
01406                                                    "Displays current editor type. "
01407                                                    "Click for menu of available types");
01408         uiButSetFunc(but, spacefunc, NULL, NULL);
01409         
01410         return xco + UI_UNIT_X + 14;
01411 }
01412 
01413 int ED_area_header_standardbuttons(const bContext *C, uiBlock *block, int yco)
01414 {
01415         ScrArea *sa= CTX_wm_area(C);
01416         int xco= 8;
01417         
01418         if (!sa->full)
01419                 xco= ED_area_header_switchbutton(C, block, yco);
01420 
01421         uiBlockSetEmboss(block, UI_EMBOSSN);
01422 
01423         if (sa->flag & HEADER_NO_PULLDOWN) {
01424                 uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0, 
01425                                                  ICON_DISCLOSURE_TRI_RIGHT,
01426                                                  xco,yco,UI_UNIT_X,UI_UNIT_Y-2,
01427                                                  &(sa->flag), 0, 0, 0, 0, 
01428                                                  "Show pulldown menus");
01429         }
01430         else {
01431                 uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0, 
01432                                                  ICON_DISCLOSURE_TRI_DOWN,
01433                                                  xco,yco,UI_UNIT_X,UI_UNIT_Y-2,
01434                                                  &(sa->flag), 0, 0, 0, 0, 
01435                                                  "Hide pulldown menus");
01436         }
01437 
01438         uiBlockSetEmboss(block, UI_EMBOSS);
01439         
01440         return xco + UI_UNIT_X;
01441 }
01442 
01443 /************************ standard UI regions ************************/
01444 
01445 void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *context, int contextnr)
01446 {
01447         ScrArea *sa= CTX_wm_area(C);
01448         uiStyle *style= U.uistyles.first;
01449         uiBlock *block;
01450         PanelType *pt;
01451         Panel *panel;
01452         View2D *v2d= &ar->v2d;
01453         View2DScrollers *scrollers;
01454         int xco, yco, x, y, miny=0, w, em, header, triangle, open, newcontext= 0;
01455 
01456         if(contextnr >= 0)
01457                 newcontext= UI_view2d_tab_set(v2d, contextnr);
01458 
01459         if(vertical) {
01460                 w= v2d->cur.xmax - v2d->cur.xmin;
01461                 em= (ar->type->prefsizex)? UI_UNIT_Y/2: UI_UNIT_Y;
01462         }
01463         else {
01464                 w= UI_PANEL_WIDTH;
01465                 em= (ar->type->prefsizex)? UI_UNIT_Y/2: UI_UNIT_Y;
01466         }
01467 
01468         x= 0;
01469         y= -style->panelouter;
01470 
01471         /* create panels */
01472         uiBeginPanels(C, ar);
01473 
01474         /* set view2d view matrix for scrolling (without scrollers) */
01475         UI_view2d_view_ortho(v2d);
01476 
01477         for(pt= ar->type->paneltypes.first; pt; pt= pt->next) {
01478                 /* verify context */
01479                 if(context)
01480                         if(pt->context[0] && strcmp(context, pt->context) != 0)
01481                                 continue;
01482 
01483                 /* draw panel */
01484                 if(pt->draw && (!pt->poll || pt->poll(C, pt))) {
01485                         block= uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
01486                         panel= uiBeginPanel(sa, ar, block, pt, &open);
01487 
01488                         /* bad fixed values */
01489                         header= (pt->flag & PNL_NO_HEADER)? 0: UI_UNIT_Y;
01490                         triangle= (int)(UI_UNIT_Y * 1.1f);
01491 
01492                         if(vertical)
01493                                 y -= header;
01494 
01495                         if(pt->draw_header && header && (open || vertical)) {
01496                                 /* for enabled buttons */
01497                                 panel->layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
01498                                         triangle, header+style->panelspace, header, 1, style);
01499 
01500                                 pt->draw_header(C, panel);
01501 
01502                                 uiBlockLayoutResolve(block, &xco, &yco);
01503                                 panel->labelofs= xco - triangle;
01504                                 panel->layout= NULL;
01505                         }
01506                         else {
01507                                 panel->labelofs= 0;
01508                         }
01509 
01510                         if(open) {
01511                                 short panelContext;
01512                                 
01513                                 /* panel context can either be toolbar region or normal panels region */
01514                                 if (ar->regiontype == RGN_TYPE_TOOLS)
01515                                         panelContext= UI_LAYOUT_TOOLBAR;
01516                                 else
01517                                         panelContext= UI_LAYOUT_PANEL;
01518                                 
01519                                 panel->layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext,
01520                                         style->panelspace, 0, w-2*style->panelspace, em, style);
01521 
01522                                 pt->draw(C, panel);
01523 
01524                                 uiBlockLayoutResolve(block, &xco, &yco);
01525                                 panel->layout= NULL;
01526 
01527                                 yco -= 2*style->panelspace;
01528                                 uiEndPanel(block, w, -yco);
01529                         }
01530                         else {
01531                                 yco= 0;
01532                                 uiEndPanel(block, w, 0);
01533                         }
01534 
01535                         uiEndBlock(C, block);
01536 
01537                         if(vertical) {
01538                                 if(pt->flag & PNL_NO_HEADER)
01539                                         y += yco;
01540                                 else
01541                                         y += yco-style->panelouter;
01542                         }
01543                         else {
01544                                 x += w;
01545                                 miny= MIN2(y, yco-style->panelouter-header);
01546                         }
01547                 }
01548         }
01549 
01550         if(vertical)
01551                 x += w;
01552         else
01553                 y= miny;
01554         
01555         /* in case there are no panels */
01556         if(x == 0 || y == 0) {
01557                 x= UI_PANEL_WIDTH;
01558                 y= UI_PANEL_WIDTH;
01559         }
01560 
01561         /* clear */
01562         UI_ThemeClearColor((ar->type->regionid == RGN_TYPE_PREVIEW)?TH_PREVIEW_BACK:TH_BACK);
01563         glClear(GL_COLOR_BUFFER_BIT);
01564         
01565         /* before setting the view */
01566         if(vertical) {
01567                 /* only allow scrolling in vertical direction */
01568                 v2d->keepofs |= V2D_LOCKOFS_X|V2D_KEEPOFS_Y;
01569                 v2d->keepofs &= ~(V2D_LOCKOFS_Y|V2D_KEEPOFS_X);
01570                 v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
01571                 v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE;
01572                 
01573                 // don't jump back when panels close or hide
01574                 if(!newcontext)
01575                         y= MAX2(-y, -v2d->cur.ymin);
01576                 else
01577                         y= -y;
01578         }
01579         else {
01580                 /* for now, allow scrolling in both directions (since layouts are optimised for vertical,
01581                  * they often don't fit in horizontal layout)
01582                  */
01583                 v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_LOCKOFS_Y|V2D_KEEPOFS_X|V2D_KEEPOFS_Y);
01584                 //v2d->keepofs |= V2D_LOCKOFS_Y|V2D_KEEPOFS_X;
01585                 //v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_KEEPOFS_Y);
01586                 v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE;
01587                 v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_HIDE;
01588                 
01589                 // don't jump back when panels close or hide
01590                 if(!newcontext)
01591                         x= MAX2(x, v2d->cur.xmax);
01592                 y= -y;
01593         }
01594 
01595         // +V2D_SCROLL_HEIGHT is workaround to set the actual height
01596         UI_view2d_totRect_set(v2d, x+V2D_SCROLL_WIDTH, y+V2D_SCROLL_HEIGHT);
01597 
01598         /* set the view */
01599         UI_view2d_view_ortho(v2d);
01600 
01601         /* this does the actual drawing! */
01602         uiEndPanels(C, ar);
01603         
01604         /* restore view matrix */
01605         UI_view2d_view_restore(C);
01606         
01607         /* scrollers */
01608         scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
01609         UI_view2d_scrollers_draw(C, v2d, scrollers);
01610         UI_view2d_scrollers_free(scrollers);
01611 }
01612 
01613 void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
01614 {
01615         wmKeyMap *keymap;
01616         
01617         // XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file)
01618                 // scrollbars for button regions
01619         ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); 
01620         ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
01621         ar->v2d.scroll &= ~V2D_SCROLL_VERTICAL_HIDE;
01622         ar->v2d.keepzoom |= V2D_KEEPZOOM;
01623 
01624                 // correctly initialised User-Prefs?
01625         if(!(ar->v2d.align & V2D_ALIGN_NO_POS_Y))
01626                 ar->v2d.flag &= ~V2D_IS_INITIALISED;
01627         
01628         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
01629 
01630         keymap= WM_keymap_find(wm->defaultconf, "View2D Buttons List", 0, 0);
01631         WM_event_add_keymap_handler(&ar->handlers, keymap);
01632 }
01633 
01634 void ED_region_header(const bContext *C, ARegion *ar)
01635 {
01636         uiStyle *style= U.uistyles.first;
01637         uiBlock *block;
01638         uiLayout *layout;
01639         HeaderType *ht;
01640         Header header = {NULL};
01641         int maxco, xco, yco;
01642         int headery= ED_area_headersize();
01643 
01644         /* clear */     
01645         UI_ThemeClearColor((ED_screen_area_active(C))?TH_HEADER:TH_HEADERDESEL);
01646         glClear(GL_COLOR_BUFFER_BIT);
01647         
01648         /* set view2d view matrix for scrolling (without scrollers) */
01649         UI_view2d_view_ortho(&ar->v2d);
01650 
01651         xco= maxco= 8;
01652         yco= headery-4;
01653 
01654         /* draw all headers types */
01655         for(ht= ar->type->headertypes.first; ht; ht= ht->next) {
01656                 block= uiBeginBlock(C, ar, ht->idname, UI_EMBOSS);
01657                 layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, UI_UNIT_Y, 1, style);
01658 
01659                 if(ht->draw) {
01660                         header.type= ht;
01661                         header.layout= layout;
01662                         ht->draw(C, &header);
01663                         
01664                         /* for view2d */
01665                         xco= uiLayoutGetWidth(layout);
01666                         if(xco > maxco)
01667                                 maxco= xco;
01668                 }
01669 
01670                 uiBlockLayoutResolve(block, &xco, &yco);
01671                 
01672                 /* for view2d */
01673                 if(xco > maxco)
01674                         maxco= xco;
01675                 
01676                 uiEndBlock(C, block);
01677                 uiDrawBlock(C, block);
01678         }
01679 
01680         /* always as last  */
01681         UI_view2d_totRect_set(&ar->v2d, maxco+UI_UNIT_X+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
01682 
01683         /* restore view matrix? */
01684         UI_view2d_view_restore(C);
01685 }
01686 
01687 void ED_region_header_init(ARegion *ar)
01688 {
01689         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
01690 }
01691 
01692 /* UI_UNIT_Y is defined as U variable now, depending dpi */
01693 int ED_area_headersize(void)
01694 {
01695         return UI_UNIT_Y+6;
01696 }