svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r23023:HEAD
[blender.git] / source / blender / editors / screen / area.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_screen_types.h"
35 #include "DNA_userdef_types.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_arithb.h"
39 #include "BLI_rand.h"
40
41 #include "BKE_context.h"
42 #include "BKE_global.h"
43 #include "BKE_screen.h"
44 #include "BKE_utildefines.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48 #include "wm_subwindow.h"
49
50 #include "ED_screen.h"
51 #include "ED_screen_types.h"
52 #include "ED_types.h"
53
54 #include "BIF_gl.h"
55 #include "BIF_glutil.h"
56 #include "BLF_api.h"
57
58 #include "UI_interface.h"
59 #include "UI_resources.h"
60 #include "UI_view2d.h"
61
62 #ifndef DISABLE_PYTHON
63 #include "BPY_extern.h"
64 #endif
65
66 #include "screen_intern.h"
67
68 /* general area and region code */
69
70 static void region_draw_emboss(ARegion *ar, rcti *scirct)
71 {
72         rcti rect;
73         
74         /* translate scissor rect to region space */
75         rect.xmin= scirct->xmin - ar->winrct.xmin;
76         rect.ymin= scirct->ymin - ar->winrct.ymin;
77         rect.xmax= scirct->xmax - ar->winrct.xmin;
78         rect.ymax= scirct->ymax - ar->winrct.ymin;
79         
80         /* set transp line */
81         glEnable( GL_BLEND );
82         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
83         
84         /* right  */
85         glColor4ub(0,0,0, 50);
86         sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax);
87         
88         /* bottom  */
89         glColor4ub(0,0,0, 80);
90         sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin);
91         
92         /* top  */
93         glColor4ub(255,255,255, 60);
94         sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax);
95
96         /* left  */
97         glColor4ub(255,255,255, 50);
98         sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax);
99         
100         glDisable( GL_BLEND );
101 }
102
103 void ED_region_pixelspace(ARegion *ar)
104 {
105         int width= ar->winrct.xmax-ar->winrct.xmin+1;
106         int height= ar->winrct.ymax-ar->winrct.ymin+1;
107         
108         wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
109         wmLoadIdentity();
110 }
111
112 /* only exported for WM */
113 void ED_region_do_listen(ARegion *ar, wmNotifier *note)
114 {
115         /* generic notes first */
116         switch(note->category) {
117                 case NC_WM:
118                         if(note->data==ND_FILEREAD)
119                                 ED_region_tag_redraw(ar);
120                         break;
121                 case NC_WINDOW:
122                         ED_region_tag_redraw(ar);
123                         break;
124                 case NC_SCREEN:
125                         if(note->action==NA_EDITED)
126                                 ED_region_tag_redraw(ar);
127                         /* pass on */
128                 default:
129                         if(ar->type && ar->type->listener)
130                                 ar->type->listener(ar, note);
131         }
132 }
133
134 /* only exported for WM */
135 void ED_area_do_listen(ScrArea *sa, wmNotifier *note)
136 {
137         /* no generic notes? */
138         if(sa->type && sa->type->listener) {
139                 sa->type->listener(sa, note);
140         }
141 }
142
143 /* only exported for WM */
144 void ED_area_do_refresh(bContext *C, ScrArea *sa)
145 {
146         /* no generic notes? */
147         if(sa->type && sa->type->refresh) {
148                 sa->type->refresh(C, sa);
149         }
150         sa->do_refresh= 0;
151 }
152
153 /* based on screen region draw tags, set draw tags in azones, and future region tabs etc */
154 /* only exported for WM */
155 void ED_area_overdraw_flush(bContext *C, ScrArea *sa, ARegion *ar)
156 {
157         AZone *az;
158         
159         for(az= sa->actionzones.first; az; az= az->next) {
160                 int xs, ys;
161                 
162                 if(az->type==AZONE_AREA) {
163                         xs= (az->x1+az->x2)/2;
164                         ys= (az->y1+az->y2)/2;
165                 }
166                 else {
167                         xs= az->x3;
168                         ys= az->y3;
169                 }
170
171                 /* test if inside */
172                 if(BLI_in_rcti(&ar->winrct, xs, ys)) {
173                         az->do_draw= 1;
174                 }
175         }
176 }
177
178 static void area_draw_azone(short x1, short y1, short x2, short y2)
179 {
180         float xmin = x1;
181         float xmax = x2-2;
182         float ymin = y1-1;
183         float ymax = y2-3;
184         
185         float dx= 0.3f*(xmax-xmin);
186         float dy= 0.3f*(ymax-ymin);
187         
188         glColor4ub(255, 255, 255, 80);
189         fdrawline(xmin, ymax, xmax, ymin);
190         fdrawline(xmin, ymax-dy, xmax-dx, ymin);
191         fdrawline(xmin, ymax-2*dy, xmax-2*dx, ymin);
192         
193         glColor4ub(0, 0, 0, 150);
194         fdrawline(xmin, ymax+1, xmax+1, ymin);
195         fdrawline(xmin, ymax-dy+1, xmax-dx+1, ymin);
196         fdrawline(xmin, ymax-2*dy+1, xmax-2*dx+1, ymin);
197 }
198
199 static void region_draw_azone(ScrArea *sa, AZone *az)
200 {
201         if(az->ar==NULL) return;
202         
203         UI_SetTheme(sa->spacetype, az->ar->type->regionid);
204         
205         UI_ThemeColor(TH_BACK);
206         glBegin(GL_TRIANGLES);
207         glVertex2s(az->x1, az->y1);
208         glVertex2s(az->x2, az->y2);
209         glVertex2s(az->x3, az->y3);
210         glEnd();
211         
212         UI_ThemeColorShade(TH_BACK, 50);
213         sdrawline(az->x1, az->y1, az->x3, az->y3);
214         
215         UI_ThemeColorShade(TH_BACK, -50);
216         sdrawline(az->x2, az->y2, az->x3, az->y3);
217
218 }
219
220
221 /* only exported for WM */
222 void ED_area_overdraw(bContext *C)
223 {
224         wmWindow *win= CTX_wm_window(C);
225         bScreen *screen= CTX_wm_screen(C);
226         ScrArea *sa;
227         
228         /* Draw AZones, in screenspace */
229         wmSubWindowSet(win, screen->mainwin);
230
231         glEnable( GL_BLEND );
232         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
233         
234         for(sa= screen->areabase.first; sa; sa= sa->next) {
235                 AZone *az;
236                 for(az= sa->actionzones.first; az; az= az->next) {
237                         if(az->do_draw) {
238                                 if(az->type==AZONE_AREA)
239                                         area_draw_azone(az->x1, az->y1, az->x2, az->y2);
240                                 else if(az->type==AZONE_REGION)
241                                         region_draw_azone(sa, az);
242                                 
243                                 az->do_draw= 0;
244                         }
245                 }
246         }       
247         glDisable( GL_BLEND );
248         
249 }
250
251 /* get scissor rect, checking overlapping regions */
252 void region_scissor_winrct(ARegion *ar, rcti *winrct)
253 {
254         *winrct= ar->winrct;
255         
256         if(ELEM(ar->alignment, RGN_OVERLAP_LEFT, RGN_OVERLAP_RIGHT))
257                 return;
258
259         while(ar->prev) {
260                 ar= ar->prev;
261                 
262                 if(BLI_isect_rcti(winrct, &ar->winrct, NULL)) {
263                         if(ar->flag & RGN_FLAG_HIDDEN);
264                         else if(ar->alignment & RGN_SPLIT_PREV);
265                         else if(ar->alignment==RGN_OVERLAP_LEFT) {
266                                 winrct->xmin= ar->winrct.xmax + 1;
267                         }
268                         else if(ar->alignment==RGN_OVERLAP_RIGHT) {
269                                 winrct->xmax= ar->winrct.xmin - 1;
270                         }
271                         else break;
272                 }
273         }
274 }
275
276 /* only exported for WM */
277 /* makes region ready for drawing, sets pixelspace */
278 void ED_region_set(const bContext *C, ARegion *ar)
279 {
280         wmWindow *win= CTX_wm_window(C);
281         ScrArea *sa= CTX_wm_area(C);
282         rcti winrct;
283         
284         /* checks other overlapping regions */
285         region_scissor_winrct(ar, &winrct);
286         
287         ar->drawrct= winrct;
288         
289         /* note; this sets state, so we can use wmOrtho and friends */
290         wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
291         
292         UI_SetTheme(sa?sa->spacetype:0, ar->type?ar->type->regionid:0);
293         
294         ED_region_pixelspace(ar);
295 }
296
297
298 /* only exported for WM */
299 void ED_region_do_draw(bContext *C, ARegion *ar)
300 {
301         wmWindow *win= CTX_wm_window(C);
302         ScrArea *sa= CTX_wm_area(C);
303         ARegionType *at= ar->type;
304         rcti winrct;
305         
306         /* checks other overlapping regions */
307         region_scissor_winrct(ar, &winrct);
308         
309         /* if no partial draw rect set, full rect */
310         if(ar->drawrct.xmin == ar->drawrct.xmax)
311                 ar->drawrct= winrct;
312         else {
313                 /* extra clip for safety */
314                 ar->drawrct.xmin= MAX2(winrct.xmin, ar->drawrct.xmin);
315                 ar->drawrct.ymin= MAX2(winrct.ymin, ar->drawrct.ymin);
316                 ar->drawrct.xmax= MIN2(winrct.xmax, ar->drawrct.xmax);
317                 ar->drawrct.ymax= MIN2(winrct.ymax, ar->drawrct.ymax);
318         }
319         
320         /* note; this sets state, so we can use wmOrtho and friends */
321         wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
322         
323         UI_SetTheme(sa?sa->spacetype:0, ar->type?ar->type->regionid:0);
324         
325         /* optional header info instead? */
326         if(ar->headerstr) {
327                 float col[3];
328                 UI_GetThemeColor3fv(TH_HEADER, col);
329                 glClearColor(col[0], col[1], col[2], 0.0);
330                 glClear(GL_COLOR_BUFFER_BIT);
331                 
332                 UI_ThemeColor(TH_TEXT);
333                 BLF_draw_default(20, 8, 0.0f, ar->headerstr);
334         }
335         else if(at->draw) {
336                 at->draw(C, ar);
337         }
338         
339         uiFreeInactiveBlocks(C, &ar->uiblocks);
340         
341         if(sa)
342                 region_draw_emboss(ar, &winrct);
343         
344         /* XXX test: add convention to end regions always in pixel space, for drawing of borders/gestures etc */
345         ED_region_pixelspace(ar);
346         
347         ar->do_draw= 0;
348         memset(&ar->drawrct, 0, sizeof(ar->drawrct));
349 }
350
351 /* **********************************
352    maybe silly, but let's try for now
353    to keep these tags protected
354    ********************************** */
355
356 void ED_region_tag_redraw(ARegion *ar)
357 {
358         if(ar) {
359                 /* zero region means full region redraw */
360                 ar->do_draw= 1;
361                 memset(&ar->drawrct, 0, sizeof(ar->drawrct));
362         }
363 }
364
365 void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct)
366 {
367         if(ar) {
368                 if(!ar->do_draw) {
369                         /* no redraw set yet, set partial region */
370                         ar->do_draw= 1;
371                         ar->drawrct= *rct;
372                 }
373                 else if(ar->drawrct.xmin != ar->drawrct.xmax) {
374                         /* partial redraw already set, expand region */
375                         ar->drawrct.xmin= MIN2(ar->drawrct.xmin, rct->xmin);
376                         ar->drawrct.ymin= MIN2(ar->drawrct.ymin, rct->ymin);
377                         ar->drawrct.xmax= MAX2(ar->drawrct.xmax, rct->xmax);
378                         ar->drawrct.ymax= MAX2(ar->drawrct.ymax, rct->ymax);
379                 }
380         }
381 }
382
383 void ED_area_tag_redraw(ScrArea *sa)
384 {
385         ARegion *ar;
386         
387         if(sa)
388                 for(ar= sa->regionbase.first; ar; ar= ar->next)
389                         ED_region_tag_redraw(ar);
390 }
391
392 void ED_area_tag_refresh(ScrArea *sa)
393 {
394         if(sa)
395                 sa->do_refresh= 1;
396 }
397
398 /* *************************************************************** */
399
400 /* use NULL to disable it */
401 void ED_area_headerprint(ScrArea *sa, const char *str)
402 {
403         ARegion *ar;
404         
405         for(ar= sa->regionbase.first; ar; ar= ar->next) {
406                 if(ar->regiontype==RGN_TYPE_HEADER) {
407                         if(str) {
408                                 if(ar->headerstr==NULL)
409                                         ar->headerstr= MEM_mallocN(256, "headerprint");
410                                 BLI_strncpy(ar->headerstr, str, 256);
411                         }
412                         else if(ar->headerstr) {
413                                 MEM_freeN(ar->headerstr);
414                                 ar->headerstr= NULL;
415                         }
416                         ED_region_tag_redraw(ar);
417                 }
418         }
419 }
420
421 /* ************************************************************ */
422
423
424 #define AZONESPOT               12
425 static void area_azone_initialize(ScrArea *sa) 
426 {
427         AZone *az;
428         
429         /* reinitalize entirely, regions add azones too */
430         BLI_freelistN(&sa->actionzones);
431         
432         /* set area action zones */
433         az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
434         BLI_addtail(&(sa->actionzones), az);
435         az->type= AZONE_AREA;
436         az->x1= sa->totrct.xmin;
437         az->y1= sa->totrct.ymin;
438         az->x2= sa->totrct.xmin + AZONESPOT-1;
439         az->y2= sa->totrct.ymin + AZONESPOT-1;
440         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
441         
442         az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
443         BLI_addtail(&(sa->actionzones), az);
444         az->type= AZONE_AREA;
445         az->x1= sa->totrct.xmax+1;
446         az->y1= sa->totrct.ymax+1;
447         az->x2= sa->totrct.xmax-AZONESPOT+1;
448         az->y2= sa->totrct.ymax-AZONESPOT+1;
449         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
450 }
451
452 static void region_azone_initialize(ScrArea *sa, ARegion *ar, char edge) 
453 {
454         AZone *az, *azt;
455         
456         az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
457         BLI_addtail(&(sa->actionzones), az);
458         az->type= AZONE_REGION;
459         az->ar= ar;
460         az->edge= edge;
461         
462         if(edge=='t') {
463                 az->x1= ar->winrct.xmin+AZONESPOT;
464                 az->y1= ar->winrct.ymax;
465                 az->x2= ar->winrct.xmin+2*AZONESPOT;
466                 az->y2= ar->winrct.ymax;
467                 az->x3= (az->x1+az->x2)/2;
468                 az->y3= az->y2+AZONESPOT/2;
469                 BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y3);
470         }
471         else if(edge=='b') {
472                 az->x1= ar->winrct.xmin+AZONESPOT;
473                 az->y1= ar->winrct.ymin;
474                 az->x2= ar->winrct.xmin+2*AZONESPOT;
475                 az->y2= ar->winrct.ymin;
476                 az->x3= (az->x1+az->x2)/2;
477                 az->y3= az->y2-AZONESPOT/2;
478                 BLI_init_rcti(&az->rect, az->x1, az->x2, az->y3, az->y1);
479         }
480         else if(edge=='l') {
481                 az->x1= ar->winrct.xmin;
482                 az->y1= ar->winrct.ymax-AZONESPOT;
483                 az->x2= ar->winrct.xmin;
484                 az->y2= ar->winrct.ymax-2*AZONESPOT;
485                 az->x3= az->x2-AZONESPOT/2;
486                 az->y3= (az->y1+az->y2)/2;
487                 BLI_init_rcti(&az->rect, az->x3, az->x1, az->y1, az->y2);
488         }
489         else { // if(edge=='r') {
490                 az->x1= ar->winrct.xmax;
491                 az->y1= ar->winrct.ymax-AZONESPOT;
492                 az->x2= ar->winrct.xmax;
493                 az->y2= ar->winrct.ymax-2*AZONESPOT;
494                 az->x3= az->x2+AZONESPOT/2;
495                 az->y3= (az->y1+az->y2)/2;
496                 BLI_init_rcti(&az->rect, az->x1, az->x3, az->y1, az->y2);
497         }
498         
499         /* if more azones on 1 spot, set offset */
500         for(azt= sa->actionzones.first; azt; azt= azt->next) {
501                 if(az!=azt) {
502                         if( ABS(az->x1-azt->x1) < 2 && ABS(az->y1-azt->y1) < 2) {
503                                 if(edge=='t' || edge=='b') {
504                                         az->x1+= AZONESPOT;
505                                         az->x2+= AZONESPOT;
506                                         az->x3+= AZONESPOT;
507                                         BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y3);
508                                 }
509                                 else {
510                                         az->y1-= AZONESPOT;
511                                         az->y2-= AZONESPOT;
512                                         az->y3-= AZONESPOT;
513                                         BLI_init_rcti(&az->rect, az->x1, az->x3, az->y1, az->y2);
514                                 }
515                         }
516                 }
517         }
518         
519 }
520
521
522 /* *************************************************************** */
523
524 static void region_azone_add(ScrArea *sa, ARegion *ar, int alignment)
525 {
526          /* edge code (t b l r) is where azone will be drawn */
527         
528         if(alignment==RGN_ALIGN_TOP)
529                 region_azone_initialize(sa, ar, 'b');
530         else if(alignment==RGN_ALIGN_BOTTOM)
531                 region_azone_initialize(sa, ar, 't');
532         else if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT))
533                 region_azone_initialize(sa, ar, 'l');
534         else if(ELEM(alignment, RGN_ALIGN_LEFT, RGN_OVERLAP_LEFT))
535                 region_azone_initialize(sa, ar, 'r');
536                                                                 
537 }
538
539 /* dir is direction to check, not the splitting edge direction! */
540 static int rct_fits(rcti *rect, char dir, int size)
541 {
542         if(dir=='h') {
543                 return rect->xmax-rect->xmin - size;
544         }
545         else { // 'v'
546                 return rect->ymax-rect->ymin - size;
547         }
548 }
549
550 static void region_rect_recursive(ScrArea *sa, ARegion *ar, rcti *remainder, int quad)
551 {
552         rcti *remainder_prev= remainder;
553         int prefsizex, prefsizey;
554         int alignment;
555         
556         if(ar==NULL)
557                 return;
558         
559         /* no returns in function, winrct gets set in the end again */
560         BLI_init_rcti(&ar->winrct, 0, 0, 0, 0);
561         
562         /* for test; allow split of previously defined region */
563         if(ar->alignment & RGN_SPLIT_PREV)
564                 if(ar->prev)
565                         remainder= &ar->prev->winrct;
566         
567         alignment = ar->alignment & ~RGN_SPLIT_PREV;
568         
569         /* clear state flags first */
570         ar->flag &= ~RGN_FLAG_TOO_SMALL;
571         /* user errors */
572         if(ar->next==NULL && alignment!=RGN_ALIGN_QSPLIT)
573                 alignment= RGN_ALIGN_NONE;
574         
575         prefsizex= ar->type->minsizex;
576         prefsizey= ar->type->minsizey;
577         
578         /* hidden is user flag */
579         if(ar->flag & RGN_FLAG_HIDDEN);
580         /* XXX floating area region, not handled yet here */
581         else if(alignment == RGN_ALIGN_FLOAT);
582         /* remainder is too small for any usage */
583         else if( rct_fits(remainder, 'v', 1)<0 || rct_fits(remainder, 'h', 1) < 0 ) {
584                 ar->flag |= RGN_FLAG_TOO_SMALL;
585         }
586         else if(alignment==RGN_ALIGN_NONE) {
587                 /* typically last region */
588                 ar->winrct= *remainder;
589                 BLI_init_rcti(remainder, 0, 0, 0, 0);
590         }
591         else if(alignment==RGN_ALIGN_TOP || alignment==RGN_ALIGN_BOTTOM) {
592                 
593                 if( rct_fits(remainder, 'v', prefsizey) < 0 ) {
594                         ar->flag |= RGN_FLAG_TOO_SMALL;
595                 }
596                 else {
597                         int fac= rct_fits(remainder, 'v', prefsizey);
598
599                         if(fac < 0 )
600                                 prefsizey += fac;
601                         
602                         ar->winrct= *remainder;
603                         
604                         if(alignment==RGN_ALIGN_TOP) {
605                                 ar->winrct.ymin= ar->winrct.ymax - prefsizey + 1;
606                                 remainder->ymax= ar->winrct.ymin - 1;
607                         }
608                         else {
609                                 ar->winrct.ymax= ar->winrct.ymin + prefsizey - 1;
610                                 remainder->ymin= ar->winrct.ymax + 1;
611                         }
612                 }
613         }
614         else if( ELEM4(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT, RGN_OVERLAP_LEFT, RGN_OVERLAP_RIGHT)) {
615                 
616                 if( rct_fits(remainder, 'h', prefsizex) < 0 ) {
617                         ar->flag |= RGN_FLAG_TOO_SMALL;
618                 }
619                 else {
620                         int fac= rct_fits(remainder, 'h', prefsizex);
621                         
622                         if(fac < 0 )
623                                 prefsizex += fac;
624                         
625                         ar->winrct= *remainder;
626                         
627                         if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT)) {
628                                 ar->winrct.xmin= ar->winrct.xmax - prefsizex + 1;
629                                 if(alignment==RGN_ALIGN_RIGHT)
630                                         remainder->xmax= ar->winrct.xmin - 1;
631                         }
632                         else {
633                                 ar->winrct.xmax= ar->winrct.xmin + prefsizex - 1;
634                                 if(alignment==RGN_ALIGN_LEFT)
635                                         remainder->xmin= ar->winrct.xmax + 1;
636                         }
637                 }
638         }
639         else if(alignment==RGN_ALIGN_VSPLIT || alignment==RGN_ALIGN_HSPLIT) {
640                 /* percentage subdiv*/
641                 ar->winrct= *remainder;
642                 
643                 if(alignment==RGN_ALIGN_HSPLIT) {
644                         if( rct_fits(remainder, 'h', prefsizex) > 4) {
645                                 ar->winrct.xmax= (remainder->xmin+remainder->xmax)/2;
646                                 remainder->xmin= ar->winrct.xmax+1;
647                         }
648                         else {
649                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
650                         }
651                 }
652                 else {
653                         if( rct_fits(remainder, 'v', prefsizey) > 4) {
654                                 ar->winrct.ymax= (remainder->ymin+remainder->ymax)/2;
655                                 remainder->ymin= ar->winrct.ymax+1;
656                         }
657                         else {
658                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
659                         }
660                 }
661         }
662         else if(alignment==RGN_ALIGN_QSPLIT) {
663                 ar->winrct= *remainder;
664                 
665                 /* test if there's still 4 regions left */
666                 if(quad==0) {
667                         ARegion *artest= ar->next;
668                         int count= 1;
669                         
670                         while(artest) {
671                                 artest->alignment= RGN_ALIGN_QSPLIT;
672                                 artest= artest->next;
673                                 count++;
674                         }
675                         
676                         if(count!=4) {
677                                 /* let's stop adding regions */
678                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
679                                 printf("region quadsplit failed\n");
680                         }
681                         else quad= 1;
682                 }
683                 if(quad) {
684                         if(quad==1) { /* left bottom */
685                                 ar->winrct.xmax = (remainder->xmin + remainder->xmax)/2;
686                                 ar->winrct.ymax = (remainder->ymin + remainder->ymax)/2;
687                         }
688                         else if(quad==2) { /* left top */
689                                 ar->winrct.xmax = (remainder->xmin + remainder->xmax)/2;
690                                 ar->winrct.ymin = 1 + (remainder->ymin + remainder->ymax)/2;
691                         }
692                         else if(quad==3) { /* right bottom */
693                                 ar->winrct.xmin = 1 + (remainder->xmin + remainder->xmax)/2;
694                                 ar->winrct.ymax = (remainder->ymin + remainder->ymax)/2;
695                         }
696                         else {  /* right top */
697                                 ar->winrct.xmin = 1 + (remainder->xmin + remainder->xmax)/2;
698                                 ar->winrct.ymin = 1 + (remainder->ymin + remainder->ymax)/2;
699                                 BLI_init_rcti(remainder, 0, 0, 0, 0);
700                         }
701
702                         quad++;
703                 }
704         }
705         
706         /* for speedup */
707         ar->winx= ar->winrct.xmax - ar->winrct.xmin + 1;
708         ar->winy= ar->winrct.ymax - ar->winrct.ymin + 1;
709         
710         /* restore test exception */
711         if(ar->alignment & RGN_SPLIT_PREV) {
712                 if(ar->prev) {
713                         remainder= remainder_prev;
714                         ar->prev->winx= ar->prev->winrct.xmax - ar->prev->winrct.xmin + 1;
715                         ar->prev->winy= ar->prev->winrct.ymax - ar->prev->winrct.ymin + 1;
716                 }
717         }
718
719         /* set winrect for azones */
720         if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
721                 ar->winrct= *remainder;
722                 
723                 if(alignment==RGN_ALIGN_TOP)
724                         ar->winrct.ymin= ar->winrct.ymax;
725                 else if(alignment==RGN_ALIGN_BOTTOM)
726                         ar->winrct.ymax= ar->winrct.ymin;
727                 else if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT))
728                         ar->winrct.xmin= ar->winrct.xmax;
729                 else if(ELEM(alignment, RGN_ALIGN_LEFT, RGN_OVERLAP_LEFT))
730                         ar->winrct.xmax= ar->winrct.xmin;
731                 else /* prevent winrct to be valid */
732                         ar->winrct.xmax= ar->winrct.xmin;
733         }
734         /* in end, add azones, where appropriate */
735         region_azone_add(sa, ar, alignment);
736
737
738         region_rect_recursive(sa, ar->next, remainder, quad);
739 }
740
741 static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
742 {
743         short rt= CLAMPIS(G.rt, 0, 16);
744
745         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1+rt;
746         else sa->totrct.xmin= sa->v1->vec.x;
747         if(sa->v4->vec.x<sizex-1) sa->totrct.xmax= sa->v4->vec.x-1-rt;
748         else sa->totrct.xmax= sa->v4->vec.x;
749         
750         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1+rt;
751         else sa->totrct.ymin= sa->v1->vec.y;
752         if(sa->v2->vec.y<sizey-1) sa->totrct.ymax= sa->v2->vec.y-1-rt;
753         else sa->totrct.ymax= sa->v2->vec.y;
754         
755         /* for speedup */
756         sa->winx= sa->totrct.xmax-sa->totrct.xmin+1;
757         sa->winy= sa->totrct.ymax-sa->totrct.ymin+1;
758 }
759
760
761 /* used for area initialize below */
762 static void region_subwindow(wmWindowManager *wm, wmWindow *win, ARegion *ar)
763 {
764         if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
765                 if(ar->swinid)
766                         wm_subwindow_close(win, ar->swinid);
767                 ar->swinid= 0;
768         }
769         else if(ar->swinid==0)
770                 ar->swinid= wm_subwindow_open(win, &ar->winrct);
771         else 
772                 wm_subwindow_position(win, ar->swinid, &ar->winrct);
773 }
774
775 static void ed_default_handlers(wmWindowManager *wm, ListBase *handlers, int flag)
776 {
777         /* note, add-handler checks if it already exists */
778         
779         // XXX it would be good to have boundbox checks for some of these...
780         if(flag & ED_KEYMAP_UI) {
781                 UI_add_region_handlers(handlers);
782         }
783         if(flag & ED_KEYMAP_VIEW2D) {
784                 ListBase *keymap= WM_keymap_listbase(wm, "View2D", 0, 0);
785                 WM_event_add_keymap_handler(handlers, keymap);
786         }
787         if(flag & ED_KEYMAP_MARKERS) {
788                 ListBase *keymap= WM_keymap_listbase(wm, "Markers", 0, 0);
789                 WM_event_add_keymap_handler(handlers, keymap);
790                 // XXX need boundbox check urgently!!!
791         }
792         if(flag & ED_KEYMAP_ANIMATION) {
793                 ListBase *keymap= WM_keymap_listbase(wm, "Animation", 0, 0);
794                 WM_event_add_keymap_handler(handlers, keymap);
795         }
796         if(flag & ED_KEYMAP_FRAMES) {
797                 ListBase *keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
798                 WM_event_add_keymap_handler(handlers, keymap);
799         }
800         if(flag & ED_KEYMAP_GPENCIL) {
801                 ListBase *keymap= WM_keymap_listbase(wm, "Grease Pencil", 0, 0);
802                 WM_event_add_keymap_handler(handlers, keymap);
803         }
804 }
805
806
807 /* called in screen_refresh, or screens_init, also area size changes */
808 void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
809 {
810         ARegion *ar;
811         rcti rect;
812         
813         /* set typedefinitions */
814         sa->type= BKE_spacetype_from_id(sa->spacetype);
815         
816         if(sa->type==NULL) {
817                 sa->butspacetype= sa->spacetype= SPACE_VIEW3D;
818                 sa->type= BKE_spacetype_from_id(sa->spacetype);
819         }
820         
821         for(ar= sa->regionbase.first; ar; ar= ar->next)
822                 ar->type= BKE_regiontype_from_id(sa->type, ar->regiontype);
823         
824         /* area sizes */
825         area_calc_totrct(sa, win->sizex, win->sizey);
826         
827         /* clear all azones, add the area triange widgets */
828         area_azone_initialize(sa);
829
830         /* region rect sizes */
831         rect= sa->totrct;
832         region_rect_recursive(sa, sa->regionbase.first, &rect, 0);
833         
834         /* default area handlers */
835         ed_default_handlers(wm, &sa->handlers, sa->type->keymapflag);
836         /* checks spacedata, adds own handlers */
837         if(sa->type->init)
838                 sa->type->init(wm, sa);
839         
840         /* region windows, default and own handlers */
841         for(ar= sa->regionbase.first; ar; ar= ar->next) {
842                 region_subwindow(wm, win, ar);
843                 
844                 if(ar->swinid) {
845                         /* default region handlers */
846                         ed_default_handlers(wm, &ar->handlers, ar->type->keymapflag);
847
848                         if(ar->type->init)
849                                 ar->type->init(wm, ar);
850                 }
851                 else {
852                         /* prevent uiblocks to run */
853                         uiFreeBlocks(NULL, &ar->uiblocks);      
854                 }
855                 
856         }
857 }
858
859 /* externally called for floating regions like menus */
860 void ED_region_init(bContext *C, ARegion *ar)
861 {
862 //      ARegionType *at= ar->type;
863         
864         /* refresh can be called before window opened */
865         region_subwindow(CTX_wm_manager(C), CTX_wm_window(C), ar);
866         
867         ar->winx= ar->winrct.xmax - ar->winrct.xmin + 1;
868         ar->winy= ar->winrct.ymax - ar->winrct.ymin + 1;
869         
870         /* UI convention */
871         wmLoadIdentity();
872         wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f);
873         
874 }
875
876
877 /* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
878 /* area vertices were set */
879 void area_copy_data(ScrArea *sa1, ScrArea *sa2, int swap_space)
880 {
881         SpaceType *st;
882         ARegion *ar;
883         
884         sa1->headertype= sa2->headertype;
885         sa1->spacetype= sa2->spacetype;
886         sa1->butspacetype= sa2->butspacetype;
887         
888         if(swap_space == 1) {
889                 SWAP(ListBase, sa1->spacedata, sa2->spacedata);
890                 /* exception: ensure preview is reset */
891 //              if(sa1->spacetype==SPACE_VIEW3D)
892 // XXX                  BIF_view3d_previewrender_free(sa1->spacedata.first);
893         }
894         else if (swap_space == 2) {
895                 BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
896         }
897         else {
898                 BKE_spacedata_freelist(&sa1->spacedata);
899                 BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
900         }
901         
902         /* Note; SPACE_EMPTY is possible on new screens */
903         
904         /* regions */
905         if(swap_space<2) {
906                 st= BKE_spacetype_from_id(sa1->spacetype);
907                 for(ar= sa1->regionbase.first; ar; ar= ar->next)
908                         BKE_area_region_free(st, ar);
909                 BLI_freelistN(&sa1->regionbase);
910         }
911         
912         st= BKE_spacetype_from_id(sa2->spacetype);
913         for(ar= sa2->regionbase.first; ar; ar= ar->next) {
914                 ARegion *newar= BKE_area_region_copy(st, ar);
915                 BLI_addtail(&sa1->regionbase, newar);
916         }
917 }
918
919 /* *********** Space switching code *********** */
920
921 void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
922 {
923         ScrArea *tmp= MEM_callocN(sizeof(ScrArea), "addscrarea");
924
925         ED_area_exit(C, sa1);
926         ED_area_exit(C, sa2);
927
928         tmp->spacetype= sa1->spacetype;
929         tmp->butspacetype= sa1->butspacetype;
930         BKE_spacedata_copyfirst(&tmp->spacedata, &sa1->spacedata);
931
932         area_copy_data(tmp, sa1, 2);
933         area_copy_data(sa1, sa2, 0);
934         area_copy_data(sa2, tmp, 0);
935         ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa1);
936         ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa2);
937
938         BKE_screen_area_free(tmp);
939         MEM_freeN(tmp);
940
941         /* tell WM to refresh, cursor types etc */
942         WM_event_add_mousemove(C);
943         
944         ED_area_tag_redraw(sa1);
945         ED_area_tag_refresh(sa1);
946         ED_area_tag_redraw(sa2);
947         ED_area_tag_refresh(sa2);
948 }
949
950 void ED_area_newspace(bContext *C, ScrArea *sa, int type)
951 {
952         if(sa->spacetype != type) {
953                 SpaceType *st;
954                 SpaceLink *slold;
955                 SpaceLink *sl;
956
957                 ED_area_exit(C, sa);
958
959                 st= BKE_spacetype_from_id(type);
960                 slold= sa->spacedata.first;
961
962                 sa->spacetype= type;
963                 sa->butspacetype= type;
964                 sa->type= st;
965                 
966                 /* check previously stored space */
967                 for (sl= sa->spacedata.first; sl; sl= sl->next)
968                         if(sl->spacetype==type)
969                                 break;
970                 
971                 /* old spacedata... happened during work on 2.50, remove */
972                 if(sl && sl->regionbase.first==NULL) {
973                         st->free(sl);
974                         BLI_freelinkN(&sa->spacedata, sl);
975                         sl= NULL;
976                 }
977                 
978                 if (sl) {
979                         
980                         /* swap regions */
981                         slold->regionbase= sa->regionbase;
982                         sa->regionbase= sl->regionbase;
983                         sl->regionbase.first= sl->regionbase.last= NULL;
984                         
985                         /* put in front of list */
986                         BLI_remlink(&sa->spacedata, sl);
987                         BLI_addhead(&sa->spacedata, sl);
988                 } 
989                 else {
990                         /* new space */
991                         if(st) {
992                                 sl= st->new(C);
993                                 BLI_addhead(&sa->spacedata, sl);
994                                 
995                                 /* swap regions */
996                                 if(slold)
997                                         slold->regionbase= sa->regionbase;
998                                 sa->regionbase= sl->regionbase;
999                                 sl->regionbase.first= sl->regionbase.last= NULL;
1000                         }
1001                 }
1002                 
1003                 ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
1004                 
1005                 /* tell WM to refresh, cursor types etc */
1006                 WM_event_add_mousemove(C);
1007                 
1008                 ED_area_tag_redraw(sa);
1009                 ED_area_tag_refresh(sa);
1010         }
1011 }
1012
1013 void ED_area_prevspace(bContext *C)
1014 {
1015         SpaceLink *sl= CTX_wm_space_data(C);
1016         ScrArea *sa= CTX_wm_area(C);
1017
1018         /* cleanup */
1019 #if 0 // XXX needs to be space type specific
1020         if(sfile->spacetype==SPACE_FILE) {
1021                 if(sfile->pupmenu) {
1022                         MEM_freeN(sfile->pupmenu);
1023                         sfile->pupmenu= NULL;
1024                 }
1025         }
1026 #endif
1027
1028         if(sl->next) {
1029
1030 #if 0 // XXX check whether this is still needed
1031                 if (sfile->spacetype == SPACE_SCRIPT) {
1032                         SpaceScript *sc = (SpaceScript *)sfile;
1033                         if (sc->script) sc->script->flags &=~SCRIPT_FILESEL;
1034                 }
1035 #endif
1036
1037                 ED_area_newspace(C, sa, sl->next->spacetype);
1038         }
1039         else {
1040                 ED_area_newspace(C, sa, SPACE_INFO);
1041         }
1042         ED_area_tag_redraw(sa);
1043 }
1044
1045 static char *windowtype_pup(void)
1046 {
1047         return(
1048                    "Window type:%t"
1049                    "|3D View %x1"
1050
1051                    "|%l"
1052                    
1053                    "|Timeline %x15"
1054                    "|Graph Editor %x2"
1055                    "|DopeSheet %x12"
1056                    "|NLA Editor %x13"
1057                    
1058                    "|%l"
1059                    
1060                    "|UV/Image Editor %x6"
1061                    
1062                    "|Video Sequence Editor %x8"
1063                    "|Text Editor %x9" 
1064                    "|Node Editor %x16"
1065                    "|Logic Editor %x17"
1066                    
1067                    "|%l"
1068                    
1069                    "|Properties %x4"
1070                    "|Outliner %x3"
1071                    "|User Preferences %x19"
1072                    "|Info%x7"
1073                                    
1074                    "|%l"
1075                    
1076                    "|File Browser %x5"
1077                    
1078                    "|%l"
1079                    
1080                    "|Console %x18"
1081                    );
1082 }
1083
1084 static void spacefunc(struct bContext *C, void *arg1, void *arg2)
1085 {
1086         ED_area_newspace(C, CTX_wm_area(C), CTX_wm_area(C)->butspacetype);
1087         ED_area_tag_redraw(CTX_wm_area(C));
1088 }
1089
1090 /* returns offset for next button in header */
1091 int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
1092 {
1093         ScrArea *sa= CTX_wm_area(C);
1094         uiBut *but;
1095         int xco= 8;
1096         
1097         but= uiDefIconTextButC(block, ICONTEXTROW, 0, ICON_VIEW3D, 
1098                                                    windowtype_pup(), xco, yco, XIC+10, YIC, 
1099                                                    &(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0, 
1100                                                    "Displays Current Window Type. "
1101                                                    "Click for menu of available types.");
1102         uiButSetFunc(but, spacefunc, NULL, NULL);
1103         
1104         return xco + XIC + 14;
1105 }
1106
1107 int ED_area_header_standardbuttons(const bContext *C, uiBlock *block, int yco)
1108 {
1109         ScrArea *sa= CTX_wm_area(C);
1110         int xco= 8;
1111         
1112         xco= ED_area_header_switchbutton(C, block, yco);
1113
1114         uiBlockSetEmboss(block, UI_EMBOSSN);
1115
1116         if (sa->flag & HEADER_NO_PULLDOWN) {
1117                 uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0, 
1118                                                  ICON_DISCLOSURE_TRI_RIGHT,
1119                                                  xco,yco,XIC,YIC-2,
1120                                                  &(sa->flag), 0, 0, 0, 0, 
1121                                                  "Show pulldown menus");
1122         }
1123         else {
1124                 uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0, 
1125                                                  ICON_DISCLOSURE_TRI_DOWN,
1126                                                  xco,yco,XIC,YIC-2,
1127                                                  &(sa->flag), 0, 0, 0, 0, 
1128                                                  "Hide pulldown menus");
1129         }
1130
1131         uiBlockSetEmboss(block, UI_EMBOSS);
1132         
1133         return xco + XIC;
1134 }
1135
1136 /************************ standard UI regions ************************/
1137
1138 void ED_region_panels(const bContext *C, ARegion *ar, int vertical, char *context, int contextnr)
1139 {
1140         ScrArea *sa= CTX_wm_area(C);
1141         uiStyle *style= U.uistyles.first;
1142         uiBlock *block;
1143         PanelType *pt;
1144         Panel *panel;
1145         View2D *v2d= &ar->v2d;
1146         View2DScrollers *scrollers;
1147         float col[3];
1148         int xco, yco, x, y, miny=0, w, em, header, triangle, open, newcontext= 0;
1149
1150         if(contextnr >= 0)
1151                 newcontext= UI_view2d_tab_set(v2d, contextnr);
1152
1153         if(vertical) {
1154                 w= v2d->cur.xmax - v2d->cur.xmin;
1155                 em= (ar->type->minsizex)? 10: 20;
1156         }
1157         else {
1158                 w= UI_PANEL_WIDTH;
1159                 em= (ar->type->minsizex)? 10: 20;
1160         }
1161
1162         x= 0;
1163         y= -style->panelouter;
1164
1165         /* create panels */
1166         uiBeginPanels(C, ar);
1167
1168         /* set view2d view matrix for scrolling (without scrollers) */
1169         UI_view2d_view_ortho(C, v2d);
1170
1171         for(pt= ar->type->paneltypes.first; pt; pt= pt->next) {
1172                 /* verify context */
1173                 if(context)
1174                         if(pt->context[0] && strcmp(context, pt->context) != 0)
1175                                 continue;
1176
1177                 /* draw panel */
1178                 if(pt->draw && (!pt->poll || pt->poll(C, pt))) {
1179                         block= uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
1180                         panel= uiBeginPanel(sa, ar, block, pt, &open);
1181
1182                         /* bad fixed values */
1183                         header= (pt->flag & PNL_NO_HEADER)? 0: 20;
1184                         triangle= 22;
1185
1186                         if(vertical)
1187                                 y -= header;
1188
1189                         if(pt->draw_header && header && (open || vertical)) {
1190                                 /* for enabled buttons */
1191                                 panel->layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
1192                                         triangle, header+style->panelspace, header, 1, style);
1193
1194                                 pt->draw_header(C, panel);
1195
1196                                 uiBlockLayoutResolve(C, block, &xco, &yco);
1197                                 panel->labelofs= xco - triangle;
1198                                 panel->layout= NULL;
1199                         }
1200
1201                         if(open) {
1202                                 panel->layout= uiBlockLayout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL,
1203                                         style->panelspace, 0, w-2*style->panelspace, em, style);
1204
1205                                 pt->draw(C, panel);
1206
1207                                 uiBlockLayoutResolve(C, block, &xco, &yco);
1208                                 panel->layout= NULL;
1209
1210                                 yco -= 2*style->panelspace;
1211                                 uiEndPanel(block, w, -yco);
1212                         }
1213                         else {
1214                                 yco= 0;
1215                                 uiEndPanel(block, w, 0);
1216                         }
1217
1218                         uiEndBlock(C, block);
1219
1220                         if(vertical) {
1221                                 if(pt->flag & PNL_NO_HEADER)
1222                                         y += yco;
1223                                 else
1224                                         y += yco-style->panelouter;
1225                         }
1226                         else {
1227                                 x += w;
1228                                 miny= MIN2(y, yco-style->panelouter-header);
1229                         }
1230                 }
1231         }
1232
1233         if(vertical)
1234                 x += w;
1235         else
1236                 y= miny;
1237         
1238         /* in case there are no panels */
1239         if(x == 0 || y == 0) {
1240                 x= UI_PANEL_WIDTH;
1241                 y= UI_PANEL_WIDTH;
1242         }
1243
1244         /* clear */
1245         UI_GetThemeColor3fv(TH_BACK, col);
1246         glClearColor(col[0], col[1], col[2], 0.0);
1247         glClear(GL_COLOR_BUFFER_BIT);
1248
1249         /* before setting the view */
1250         if(vertical) {
1251                 /* only allow scrolling in vertical direction */
1252                 v2d->keepofs |= V2D_LOCKOFS_X|V2D_KEEPOFS_Y;
1253                 v2d->keepofs &= ~(V2D_LOCKOFS_Y|V2D_KEEPOFS_X);
1254                 
1255                 // don't jump back when panels close or hide
1256                 if(!newcontext)
1257                         y= MAX2(-y, -v2d->cur.ymin);
1258                 else
1259                         y= -y;
1260         }
1261         else {
1262                 /* for now, allow scrolling in both directions (since layouts are optimised for vertical,
1263                  * they often don't fit in horizontal layout)
1264                  */
1265                 v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_LOCKOFS_Y|V2D_KEEPOFS_X|V2D_KEEPOFS_Y);
1266                 //v2d->keepofs |= V2D_LOCKOFS_Y|V2D_KEEPOFS_X;
1267                 //v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_KEEPOFS_Y);
1268                 
1269                 // don't jump back when panels close or hide
1270                 if(!newcontext)
1271                         x= MAX2(x, v2d->cur.xmax);
1272                 y= -y;
1273         }
1274
1275         // +V2D_SCROLL_HEIGHT is workaround to set the actual height
1276         UI_view2d_totRect_set(v2d, x+V2D_SCROLL_WIDTH, y+V2D_SCROLL_HEIGHT);
1277
1278         /* set the view */
1279         UI_view2d_view_ortho(C, v2d);
1280
1281         /* this does the actual drawing! */
1282         uiEndPanels(C, ar);
1283         
1284         /* restore view matrix */
1285         UI_view2d_view_restore(C);
1286         
1287         /* scrollers */
1288         scrollers= UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
1289         UI_view2d_scrollers_draw(C, v2d, scrollers);
1290         UI_view2d_scrollers_free(scrollers);
1291 }
1292
1293 void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
1294 {
1295         ListBase *keymap;
1296         
1297         // XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file)
1298                 // scrollbars for button regions
1299         ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM); 
1300         ar->v2d.keepzoom |= V2D_KEEPZOOM;
1301
1302                 // correctly initialised User-Prefs?
1303         if(!(ar->v2d.align & V2D_ALIGN_NO_POS_Y))
1304                 ar->v2d.flag &= ~V2D_IS_INITIALISED;
1305         
1306         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
1307
1308         keymap= WM_keymap_listbase(wm, "View2D Buttons List", 0, 0);
1309         WM_event_add_keymap_handler(&ar->handlers, keymap);
1310 }
1311
1312 void ED_region_header(const bContext *C, ARegion *ar)
1313 {
1314         uiStyle *style= U.uistyles.first;
1315         uiBlock *block;
1316         uiLayout *layout;
1317         HeaderType *ht;
1318         Header header = {0};
1319         float col[3];
1320         int maxco, xco, yco;
1321
1322         /* clear */
1323         if(ED_screen_area_active(C))
1324                 UI_GetThemeColor3fv(TH_HEADER, col);
1325         else
1326                 UI_GetThemeColor3fv(TH_HEADERDESEL, col);
1327         
1328         glClearColor(col[0], col[1], col[2], 0.0);
1329         glClear(GL_COLOR_BUFFER_BIT);
1330         
1331         /* set view2d view matrix for scrolling (without scrollers) */
1332         UI_view2d_view_ortho(C, &ar->v2d);
1333
1334         xco= maxco= 8;
1335         yco= HEADERY-3;
1336
1337         /* draw all headers types */
1338         for(ht= ar->type->headertypes.first; ht; ht= ht->next) {
1339                 block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS);
1340                 layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, HEADERY-6, 1, style);
1341
1342                 if(ht->draw) {
1343                         header.type= ht;
1344                         header.layout= layout;
1345                         ht->draw(C, &header);
1346                         
1347                         /* for view2d */
1348                         xco= uiLayoutGetWidth(layout);
1349                         if(xco > maxco)
1350                                 maxco= xco;
1351                 }
1352
1353                 uiBlockLayoutResolve(C, block, &xco, &yco);
1354                 
1355                 /* for view2d */
1356                 if(xco > maxco)
1357                         maxco= xco;
1358                 
1359                 uiEndBlock(C, block);
1360                 uiDrawBlock(C, block);
1361         }
1362
1363         /* always as last  */
1364         UI_view2d_totRect_set(&ar->v2d, maxco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
1365
1366         /* restore view matrix? */
1367         UI_view2d_view_restore(C);
1368 }
1369
1370 void ED_region_header_init(ARegion *ar)
1371 {
1372         UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
1373 }
1374