Bugfix #3046
[blender.git] / source / blender / src / editscreen.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * All screen functions that are related to the interface
32  * handling and drawing. Might be split up as well later...
33  */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "nla.h"
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>  /* isprint */
44 #include <stdio.h>
45 #include <math.h>
46
47 #include "MEM_guardedalloc.h"
48
49 #include "PIL_time.h"
50
51 #include "BMF_Api.h"
52
53 #include "BLI_blenlib.h"
54 #include "BLI_arithb.h"
55
56 #include "IMB_imbuf_types.h"
57 #include "IMB_imbuf.h"
58
59 #include "DNA_action_types.h"
60 #include "DNA_object_types.h"
61 #include "DNA_screen_types.h"
62 #include "DNA_space_types.h"
63 #include "DNA_sound_types.h"
64 #include "DNA_view3d_types.h"
65 #include "DNA_userdef_types.h"
66
67 #include "BLO_writefile.h"
68
69 #include "BKE_utildefines.h"
70 #include "BKE_global.h"
71 #include "BKE_library.h"
72 #include "BKE_main.h"
73 #include "BKE_blender.h"
74 #include "BKE_screen.h"
75
76 #include "BIF_editsound.h"
77 #include "BIF_glutil.h"
78 #include "BIF_gl.h"
79 #include "BIF_graphics.h"
80 #include "BIF_interface.h"
81 #include "BIF_mainqueue.h"
82 #include "BIF_mywindow.h"
83 #include "BIF_renderwin.h"
84 #include "BIF_screen.h"
85 #include "BIF_space.h"
86 #include "BIF_toets.h"
87 #include "BIF_toolbox.h"
88 #include "BIF_usiblender.h"
89 #include "BIF_keyval.h"
90 #include "BIF_resources.h"
91
92 #include "BSE_edit.h"
93 #include "BSE_filesel.h"
94 #include "BSE_headerbuttons.h"
95 #include "BSE_seqaudio.h"
96 #include "BSE_view.h"
97
98 #include "BPY_extern.h"
99 #include "mydevice.h"
100 #include "blendef.h"
101 #include "render.h"             /* R.flag */
102
103 #include "winlay.h"
104
105 /* TIPS:
106  * 
107  * - WATCH THE EDGES,  VERTICES HAVE TO BE IN ORDER...
108          (lowest pointer first). Otherwise unpredictable effects!
109  * - problem: flags here are not nicely implemented. After usage
110          always reset to zero.
111  */
112
113 static void testareas(void);
114 static void area_autoplayscreen(void);
115 static void wait_for_event(void);
116
117
118 /* ********* Globals *********** */
119
120 static Window *mainwin= NULL;
121 static int prefsizx= 0, prefsizy= 0, prefstax= 0, prefstay= 0, start_maximized= 1;
122 static short dodrawscreen= 1;
123 static ScrArea *areawinar[MAXWIN];
124 static ScrArea *g_activearea= NULL;
125 short winqueue_break= 0;
126 ScrArea *curarea= 0;
127
128 /* prototypes -------------------*/
129 int afterqtest(short win, unsigned short evt);
130 unsigned short screen_qread(short *val, char *ascii);
131 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii);
132 static void drawscredge_area(ScrArea *sa);
133
134 /**********************************************************************/
135
136 extern int textediting;
137
138 static void screen_set_cursor(bScreen *sc) 
139 {
140         if (sc->winakt>3) {
141                 ScrArea *sa= areawinar[sc->winakt];
142
143                 set_cursor(sa->cursor);
144         } else {
145                 set_cursor(CURSOR_STD);
146         }
147 }
148
149 void waitcursor(int val)
150 {
151         if(val) {
152                 set_cursor(CURSOR_WAIT);
153         } else {
154                 screen_set_cursor(G.curscreen);
155         }
156 }
157
158 static int choose_cursor(ScrArea *sa)
159 {
160         if (sa->spacetype==SPACE_VIEW3D) {
161                 if(G.obedit) return CURSOR_EDIT;
162                 else if(G.f & G_VERTEXPAINT) return CURSOR_VPAINT;
163                 else if(G.f & G_WEIGHTPAINT) return CURSOR_VPAINT;
164                 else if(G.f & G_FACESELECT) return CURSOR_FACESEL;
165                 else return CURSOR_STD;
166         } else {
167                 return CURSOR_STD;
168         }
169 }
170
171 void wich_cursor(ScrArea *sa)
172 {
173         sa->cursor= choose_cursor(sa);
174
175         screen_set_cursor(G.curscreen);
176 }
177
178
179 void setcursor_space(int spacetype, short cur)
180 {
181         bScreen *sc;
182         ScrArea *sa;
183
184         for (sc= G.main->screen.first; sc; sc= sc->id.next)
185                 for (sa= sc->areabase.first; sa; sa= sa->next)
186                         if(sa->spacetype==spacetype)
187                                 sa->cursor= cur;
188
189         screen_set_cursor(G.curscreen);
190 }
191
192
193 /* *********  IN/OUT  ************* */
194
195 void getmouseco_sc(short *mval)         /* screen coordinates */
196 {
197         getmouse(mval);
198 }
199
200 /* mouse_cursor called during a script (via Window.QHandle) need
201  * this function for getmouseco_areawin to work: */
202 void set_g_activearea(ScrArea *sa)
203 {
204         if (sa) g_activearea = sa;
205 }
206
207 void getmouseco_areawin(short *mval)            /* internal area coordinates */
208 {
209         getmouseco_sc(mval);
210         
211         if(g_activearea && g_activearea->win) {
212                 mval[0]-= g_activearea->winrct.xmin;
213                 mval[1]-= g_activearea->winrct.ymin;
214         }
215 }
216
217 void getmouseco_headwin(short *mval)            /* internal area coordinates */
218 {
219         getmouseco_sc(mval);
220         
221         if(g_activearea && g_activearea->headwin) {
222                 mval[0]-= g_activearea->headrct.xmin;
223                 mval[1]-= g_activearea->headrct.ymin;
224         }
225 }
226
227 void headerprint(char *str)
228 {
229         if(curarea->headertype) {
230                 areawinset(curarea->headwin);
231                 
232                 headerbox(curarea);
233                 
234                 BIF_ThemeColor(TH_MENU_TEXT); /* better than cpack(0x0) color no? (desoto) */
235                 glRasterPos2i(20+curarea->headbutofs,  6);
236                 BMF_DrawString(G.font, str);
237                 
238                 curarea->head_swap= WIN_BACK_OK;
239                 areawinset(curarea->win);
240         }
241         else {
242                 // dunno... thats for later (ton)
243         }
244 }
245
246 /* *********** STUFF ************** */
247
248 static int scredge_is_horizontal(ScrEdge *se)
249 {
250         return (se->v1->vec.y == se->v2->vec.y);
251 }
252
253 static ScrEdge *screen_find_active_scredge(bScreen *sc, short *mval)
254 {
255         ScrEdge *se;
256         
257         for (se= sc->edgebase.first; se; se= se->next) {
258                 if (scredge_is_horizontal(se)) {
259                         short min, max;
260                         min= MIN2(se->v1->vec.x, se->v2->vec.x);
261                         max= MAX2(se->v1->vec.x, se->v2->vec.x);
262                         
263                         if (abs(mval[1]-se->v1->vec.y)<=2 && mval[0] >= min && mval[0]<=max)
264                                 return se;
265                 } 
266                 else {
267                         short min, max;
268                         min= MIN2(se->v1->vec.y, se->v2->vec.y);
269                         max= MAX2(se->v1->vec.y, se->v2->vec.y);
270
271                         if (abs(mval[0]-se->v1->vec.x)<=2 && mval[1] >= min && mval[1]<=max)
272                                 return se;
273                 }
274         }
275         
276         return NULL;
277 }
278
279 void areawinset(short win)
280 {
281         if(win>3) {
282                 curarea= areawinar[win];
283                 if(curarea==0) {
284                         printf("error in areawinar %d ,areawinset\n", win);
285                         return;
286                 }
287                 
288                 BIF_SetTheme(curarea);
289                 
290                 switch(curarea->spacetype) {
291                 case SPACE_VIEW3D:
292                         G.vd= curarea->spacedata.first;
293                         break;
294                 case SPACE_IPO:
295                         G.sipo= curarea->spacedata.first;
296                         G.v2d= &G.sipo->v2d;
297                         break;
298                 case SPACE_BUTS:
299                         G.buts= curarea->spacedata.first;
300                         G.v2d= &G.buts->v2d;
301                         break;
302                 case SPACE_SEQ: {
303                         SpaceSeq *sseq= curarea->spacedata.first;
304                         G.v2d= &sseq->v2d;
305                         break;
306                 }
307                 case SPACE_OOPS:
308                         G.soops= curarea->spacedata.first;
309                         G.v2d= &G.soops->v2d;
310                         break;
311                 case SPACE_IMAGE:
312                         G.sima= curarea->spacedata.first;
313                         G.v2d= &G.sima->v2d;
314                         break;
315                 case SPACE_SOUND:
316                         G.ssound= curarea->spacedata.first;
317                         G.v2d= &G.ssound->v2d;
318                         break;
319                 case SPACE_ACTION:
320                         G.saction= curarea->spacedata.first;
321                         G.v2d= &G.saction->v2d;
322                         break;
323                 case SPACE_NLA:
324                         G.snla= curarea->spacedata.first;
325                         G.v2d= &G.snla->v2d;
326                         break;
327                 case SPACE_TIME:
328                         {
329                         SpaceTime *stime= curarea->spacedata.first;
330                         G.v2d= &stime->v2d;
331                         }
332                         break;
333                 default:
334                         break;
335                 }
336         }
337         
338         if(win) mywinset(win);
339 }
340
341 #define SCR_BACK 0.55
342 #define SCR_ROUND 12
343
344 void headerbox(ScrArea *area)
345 {
346         float width= area->winx;
347         int active=0;
348
349         glClearColor(SCR_BACK, SCR_BACK, SCR_BACK, 0.0);
350         glClear(GL_COLOR_BUFFER_BIT);
351
352         active= area_is_active_area(area);
353
354         if(active) BIF_ThemeColor(TH_HEADER);
355         else BIF_ThemeColor(TH_HEADERDESEL);
356
357         /* weird values here... is because of window matrix that centres buttons */
358         if(area->headertype==HEADERTOP) {
359                 uiSetRoundBox(3);
360                 uiRoundBoxEmboss(-0.5+area->headbutofs, -10.0, width-1.5+area->headbutofs, HEADERY-2.0, SCR_ROUND, active);
361         }
362         else {
363                 uiSetRoundBox(12);
364                 uiRoundBoxEmboss(-0.5+area->headbutofs, -3.5, width-1.5+area->headbutofs, HEADERY+10, SCR_ROUND, active);
365         }
366         
367         uiSetRoundBox(15);
368 }
369
370 int area_is_active_area(ScrArea *area)
371 {
372         return (g_activearea && area==g_activearea);
373 }
374
375 void scrarea_do_headdraw(ScrArea *area)
376 {
377         if (area->headertype) {
378                 areawinset(area->headwin);
379         
380                 headerbox(area);
381                 
382                 /* we make scissor test slightly smaller not to destroy rounded headers */
383                 glScissor(area->headrct.xmin+5, area->headrct.ymin, area->winx-10, HEADERY);
384                 
385                 switch(area->spacetype) {
386                 case SPACE_FILE:        file_buttons();         break;
387                 case SPACE_INFO:        info_buttons();         break;
388                 case SPACE_VIEW3D:      view3d_buttons();       break;
389                 case SPACE_IPO:         ipo_buttons();          break;
390                 case SPACE_BUTS:        buts_buttons();         break;
391                 case SPACE_SEQ:         seq_buttons();          break;
392                 case SPACE_IMAGE:       image_buttons();        break;
393                 case SPACE_IMASEL:      imasel_buttons();       break;
394                 case SPACE_OOPS:        oops_buttons();         break;
395                 case SPACE_TEXT:        text_buttons();         break;
396                 case SPACE_SCRIPT:script_buttons();             break;
397                 case SPACE_SOUND:       sound_buttons();        break;
398                 case SPACE_ACTION:      action_buttons();       break;
399                 case SPACE_NLA:         nla_buttons();          break;
400                 case SPACE_TIME:        time_buttons(area);     break;
401                 }
402
403                 //glScissor(area->winrct.xmin, area->winrct.xmax, area->winx, area->winy);
404                 area->head_swap= WIN_BACK_OK;
405         }
406 }
407 void scrarea_do_headchange(ScrArea *area)
408 {
409         float ofs= area->headbutofs;
410
411         if (area->headertype==HEADERDOWN) {
412                 bwin_ortho2(area->headwin, -0.375+ofs, area->headrct.xmax-area->headrct.xmin-0.375+ofs, -3.375, area->headrct.ymax-area->headrct.ymin-3.375+1.0);
413         } else if (area->headertype==HEADERTOP) {
414                 bwin_ortho2(area->headwin, -0.375+ofs, area->headrct.xmax-area->headrct.xmin-0.375+ofs, -2.375-1.0, area->headrct.ymax-area->headrct.ymin-2.375);
415         }
416 }
417
418
419 static void openheadwin(ScrArea *sa);
420 static void closeheadwin(ScrArea *sa);
421
422 static void scrarea_change_headertype(ScrArea *sa, int newtype) 
423 {
424         sa->headertype= newtype;
425
426         if (!newtype) {
427                 if (sa->headwin) {
428                         uiFreeBlocksWin(&sa->uiblocks, sa->headwin);
429                         closeheadwin(sa);
430                 }
431         } else {
432                 if (!sa->headwin) {
433                         openheadwin(sa);
434                 }
435         }
436
437         testareas();
438         mainqenter(DRAWEDGES, 1);
439         winqueue_break= 1;
440 }
441
442 static void headmenu(ScrArea *sa)
443 {
444         short val= pupmenu("Header %t|Top%x2|Bottom %x1|No Header %x0");
445         
446         if(val> -1) {
447                 scrarea_change_headertype(sa, val);
448         }
449 }
450
451 static void addqueue_ext(short win, unsigned short event, short val, char ascii)
452 {
453         if (win<4 || !areawinar[win]) {
454                 if(win==0) // other win ids are for mainwin & renderwin
455                         printf("bad call to addqueue: %d (%d, %d)\n", win, event, val);
456         } 
457         else {
458                 BWinEvent evt;
459                 evt.event= event;
460                 evt.val= val;
461                 evt.ascii= ascii;
462                 
463                 bwin_qadd(win, &evt);
464         }
465 }
466
467 void addqueue(short win, unsigned short event, short val)
468 {
469         addqueue_ext(win, event, val, 0);
470 }
471
472 void scrarea_queue_winredraw(ScrArea *area)
473 {
474         addqueue(area->win, REDRAW, 1);
475 }
476 void scrarea_queue_headredraw(ScrArea *area)
477 {
478         if (area->headwin) addqueue(area->headwin, REDRAW, 1);
479 }
480 void scrarea_queue_redraw(ScrArea *area)
481 {
482         scrarea_queue_winredraw(area);
483         scrarea_queue_headredraw(area);
484 }
485
486 static void scrollheader(ScrArea *area);
487 static void scrarea_dispatch_header_events(ScrArea *sa)
488 {
489         ScrArea *tempsa;
490         BWinEvent evt;
491         short do_redraw=0, do_change=0;
492         
493         areawinset(sa->headwin);
494         
495         while(bwin_qread(sa->headwin, &evt)) {
496                 if(evt.val) {
497                         if( uiDoBlocks(&curarea->uiblocks, evt.event)!=UI_NOTHING ) evt.event= 0;
498
499                         switch(evt.event) {
500                         case UI_BUT_EVENT:
501                                 do_headerbuttons(evt.val);
502                                 break;
503                         
504                         case LEFTMOUSE:
505                                 if (G.qual & LR_CTRLKEY) {
506                                         window_lower(mainwin);
507                                 } else {
508                                         window_raise(mainwin);
509                                 }
510                                 break;
511
512                         case MIDDLEMOUSE:
513                                 scrollheader(sa);
514                                 break;
515                         case RIGHTMOUSE:
516                                 headmenu(sa);
517                                 break;
518                         case REDRAW:
519                                 do_redraw= 1;
520                                 break;
521                         case CHANGED:
522                                 sa->head_swap= 0;
523                                 do_change= 1;
524                                 do_redraw= 1;
525                                 break;
526                         default:
527                                 if (winqueue_break == 0) {
528                                         scrarea_do_winhandle(sa, &evt);
529                                         if (winqueue_break == 0) areawinset(sa->headwin);
530                                 }
531                         }
532                         
533                         if(winqueue_break) return;
534                 }
535         }
536
537         /* test: does window still exist? */    
538         tempsa= areawinar[sa->headwin];
539         if(tempsa==0) return;
540         
541         /* this functional separation does not work as well as i expected... */
542         if(do_change) scrarea_do_headchange(sa);
543         if(do_redraw) scrarea_do_headdraw(sa);
544 }
545
546 static void scrarea_dispatch_events(ScrArea *sa)
547 {
548         ScrArea *tempsa;
549         BWinEvent evt;
550         short do_redraw=0, do_change=0;
551         
552         if(sa!=curarea || sa->win!=mywinget()) areawinset(sa->win);
553
554         while(bwin_qread(sa->win, &evt)) {
555                 if(evt.event==REDRAW) {
556                         do_redraw= 1;
557                 }
558                 else if(evt.event==CHANGED) {
559                         sa->win_swap= 0;
560                         do_change= 1;
561                         do_redraw= 1;
562                 }
563                 else {
564                         scrarea_do_winhandle(sa, &evt);
565                 }
566                 
567                 if(winqueue_break) return;
568         }
569
570         /* test: does window still exist */     
571         tempsa= areawinar[sa->win];
572         if(tempsa==0) return;
573
574         if (do_change || do_redraw) {
575                 areawinset(sa->win);
576                 if(do_change)
577                         scrarea_do_winchange(curarea);
578                 if(do_redraw)
579                         scrarea_do_windraw(curarea);
580         }
581 }
582
583 /***/
584
585
586 void markdirty_all()
587 {
588         ScrArea *sa;
589         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
590                 if(sa->win) {
591                         scrarea_queue_winredraw(sa);
592                         sa->win_swap &= ~WIN_FRONT_OK;
593                 }
594                 if(sa->headwin) {
595                         scrarea_queue_headredraw(sa);
596                         sa->head_swap &= ~WIN_FRONT_OK;
597                 }
598         }
599 }
600
601 /* but no redraw! */
602 void markdirty_all_back(void)
603 {
604         ScrArea *sa;
605         
606         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
607                 if(sa->win) {
608                         sa->win_swap &= ~WIN_BACK_OK;
609                 }
610                 if(sa->headwin) {
611                         sa->head_swap &= ~WIN_BACK_OK;
612                 }
613         }
614         
615         /* if needed; backbuffer selection redraw */
616         if(G.vd) G.vd->flag |= V3D_NEEDBACKBUFDRAW;
617
618 }
619
620 void markdirty_win_back(short winid)
621 {
622         ScrArea *sa= areawinar[winid];
623         if(sa) {
624                 if(sa->win==winid) sa->win_swap &= ~WIN_BACK_OK;
625                 else sa->head_swap &= ~WIN_BACK_OK;
626         }
627 }
628
629
630 int is_allowed_to_change_screen(bScreen *new)
631 {
632         /* not when curscreen is full
633          * not when obedit && old->scene!=new->scene
634          */
635         
636         if(new==0) return 0;
637         if(G.curscreen->full != SCREENNORMAL) return 0;
638         if(curarea->full) return 0;
639         if(G.obedit) {
640                 if(G.curscreen->scene!=new->scene) return 0;
641         }
642         return 1;
643 }
644
645 void splash(void *data, int datasize, char *string)
646 {
647         extern void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy);
648         ImBuf *bbuf;
649         int oldwin;
650         short val;
651
652         bbuf= IMB_ibImageFromMemory((int *)data, datasize, IB_rect);
653
654         if (bbuf) {
655                 oldwin = mywinget();
656                 mywinset(G.curscreen->mainwin);
657                 
658                 if (string) {
659                         int x, y, maxy;
660                         unsigned int *rect;
661                         
662                         rect = bbuf->rect;
663                         maxy = MIN2(bbuf->y, 18);
664
665                         for (y = 0; y < maxy; y++) {
666                                 for (x = 0; x < bbuf->x; x++) {
667                                         *rect = 0xffffffff;
668                                         rect++;
669                                 }
670                         }
671                 }
672                 glDrawBuffer(GL_FRONT);
673                 
674                 uiDrawBoxShadow(200, (prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2, (prefsizx+bbuf->x)/2, (prefsizy+bbuf->y)/2);
675                 
676                 glRasterPos2i((prefsizx-bbuf->x)/2, (prefsizy-bbuf->y)/2);      
677                 glDrawPixels(bbuf->x, bbuf->y, GL_RGBA, GL_UNSIGNED_BYTE, bbuf->rect);
678
679                 if (string) {
680                         void *font;
681                         int width;                      
682                         
683                         if (BMF_GetStringWidth(font= G.font, string) > bbuf->x)
684                                 if (BMF_GetStringWidth(font= G.fonts, string) > bbuf->x)
685                                         font= G.fontss;
686                         
687                         width= BMF_GetStringWidth(font, string);
688                                                 
689                         glColor3ub(0, 0, 0);
690                         glRasterPos2i((prefsizx-width)/2, (prefsizy-bbuf->y)/2 + 6);
691                         BMF_DrawString(font, string);
692                 }
693
694                 glFlush();
695                 glDrawBuffer(GL_BACK);
696                 
697                 IMB_freeImBuf(bbuf);
698                 
699                 // flush input buffers ....
700                 // this might break some things
701
702                 while (get_mbut()) {
703                         BIF_wait_for_statechange();
704                 }
705                 while(qtest()) {
706                         extern_qread(&val);
707                 }
708
709                 wait_for_event();
710                 
711                 mywinset(oldwin);
712                 markdirty_all();
713                 mainqenter(DRAWEDGES, 1);
714         }
715 }
716
717 static void moveareas(ScrEdge *edge);
718 static void joinarea_interactive(ScrArea *area, ScrEdge *onedge);
719 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge);
720
721 static void screen_edge_edit_event(ScrArea *actarea, ScrEdge *actedge, short evt, short val) 
722 {
723         if (val) {
724                         // don't allow users to edit full screens
725                 if (actarea && actarea->full) {
726                         return;
727                 }
728         
729                 if (evt==LEFTMOUSE) {
730                         moveareas(actedge);
731                 } else if (evt==MIDDLEMOUSE || evt==RIGHTMOUSE) {
732                         int edgeop;
733                 
734                         if (!actarea->headertype) {
735                                 edgeop= pupmenu("Split Area|Join Areas|Add Header");
736                         } else {
737                                 edgeop= pupmenu("Split Area|Join Areas|No Header");
738                         }
739
740                         if (edgeop==1) {
741                                 splitarea_interactive(actarea, actedge);
742                         } else if (edgeop==2) {
743                                 joinarea_interactive(actarea, actedge);
744                         } else if (edgeop==3) {
745                                 scrarea_change_headertype(actarea, actarea->headertype?0:HEADERDOWN);
746                         }
747                 }
748                 else blenderqread(evt, val);    // global hotkeys
749         }
750 }
751
752 /***/
753
754 extern void mywindow_init_mainwin(Window *win, int orx, int ory, int sizex, int sizey);
755 void test_scale_screen(bScreen *);
756
757 static void resize_screens(int x, int y, int w, int h) {
758         prefstax= x;
759         prefstay= y;
760         prefsizx= w;
761         prefsizy= h;
762
763         test_scale_screen(G.curscreen);
764         testareas();
765 }
766
767 static void init_mainwin(void)
768 {
769         int orx, ory, sizex, sizey;
770         
771         glEnable(GL_SCISSOR_TEST);
772
773         window_get_position(mainwin, &orx, &ory);
774         window_get_size(mainwin, &sizex, &sizey);
775
776                 /* XXX, temporary stupid fix for minimize at windows */
777         if (!sizex && !sizey) {
778                 return;
779         }
780
781         mywindow_init_mainwin(mainwin, orx, ory, sizex, sizey);
782         resize_screens(orx, ory, sizex, sizey);
783 }
784
785 /***/
786
787 static short afterqueue[MAXQUEUE][3];
788 static int nafterqitems= 0;
789
790 void addafterqueue(short win, unsigned short evt, short val)
791 {
792         if (nafterqitems<MAXQUEUE) {
793                 afterqueue[nafterqitems][0]= win;
794                 afterqueue[nafterqitems][1]= evt;
795                 afterqueue[nafterqitems][2]= val;
796                 nafterqitems++;
797         }
798 }
799
800 static void append_afterqueue(void)
801 {
802         while (nafterqitems) {
803                 short win= afterqueue[nafterqitems-1][0];
804                 unsigned short evt= afterqueue[nafterqitems-1][1];
805                 short val= afterqueue[nafterqitems-1][2];
806
807                 addqueue(win, evt, val);
808                 
809                 nafterqitems--;
810         }
811 }
812
813 /* check for event in afterqueue, used in force_draw in space.c */
814 int afterqtest(short win, unsigned short evt)
815 {
816         int a;
817         
818         for(a=0; a<nafterqitems; a++) {
819                 if(afterqueue[a][0]==win && afterqueue[a][1]==evt) return 1;
820         }
821         return 0;
822 }
823
824
825 static char ext_load_str[256]= {0, 0};
826 void add_readfile_event(char *filename)
827 {       
828         mainqenter(LOAD_FILE, 1);
829         strcpy(ext_load_str, filename);
830         BLI_convertstringcode(ext_load_str, G.sce, G.scene->r.cfra);
831 }
832
833 static short ext_reshape= 0, ext_redraw=0, ext_inputchange=0, ext_mousemove=0;
834
835 static void flush_extqd_events(void) {
836         if (ext_inputchange) {
837                 mainqenter(INPUTCHANGE, ext_inputchange);
838         } else if (ext_reshape) {
839                 mainqenter(RESHAPE, ext_redraw);
840         } else if (ext_redraw) {
841                 mainqenter(REDRAW, ext_redraw);
842         } else if (ext_mousemove) {
843                 short mouse[2];
844                 
845                 getmouseco_sc(mouse);
846                 
847                 mainqenter(MOUSEX, mouse[0]);
848                 mainqenter(MOUSEY, mouse[1]);
849         }
850         
851         ext_inputchange= ext_reshape= ext_redraw= ext_mousemove= 0;
852 }
853
854 unsigned short qtest(void)
855 {
856         if (!mainqtest()) {
857                 winlay_process_events(0);
858         }
859         
860         return mainqtest();
861 }
862
863         /* return true if events are waiting anywhere */
864 int anyqtest(void)
865 {
866         ScrArea *sa;
867
868         if (nafterqitems || qtest()) return 1;
869
870         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
871                 if (bwin_qtest(sa->win)) return 1;
872                 if (sa->headwin && bwin_qtest(sa->headwin)) return 1;
873         }
874
875         return 0;
876 }
877
878 static void wait_for_event(void)
879 {
880         while (!mainqtest()) {
881                 winlay_process_events(1);
882         }
883 }
884
885 unsigned short screen_qread(short *val, char *ascii)
886 {
887         unsigned short event;
888
889         wait_for_event();
890
891         event= mainqread(val, ascii);
892         
893         if(event==RIGHTSHIFTKEY || event==LEFTSHIFTKEY) {
894                 if(*val) G.qual |= LR_SHIFTKEY;
895                 else G.qual &= ~LR_SHIFTKEY;
896         }
897         else if(event==RIGHTALTKEY || event==LEFTALTKEY) {
898                 if(*val) G.qual |= LR_ALTKEY;
899                 else G.qual &= ~LR_ALTKEY;
900         }
901         else if(event==RIGHTCTRLKEY || event==LEFTCTRLKEY) {
902                 if(*val) G.qual |= LR_CTRLKEY;
903                 else G.qual &= ~LR_CTRLKEY;
904         }
905         else if(event==COMMANDKEY) {            // OSX
906                 if(*val) G.qual |= LR_COMMANDKEY;
907                 else G.qual &= ~LR_COMMANDKEY;
908         }
909
910         return event;
911 }
912
913 unsigned short extern_qread_ext(short *val, char *ascii)
914 {
915         /* stores last INPUTCHANGE and last REDRAW */
916         unsigned short event;
917         
918         event= screen_qread(val, ascii);
919         if(event==RESHAPE) ext_reshape= *val;
920         else if(event==REDRAW) ext_redraw= *val;
921         else if(event==INPUTCHANGE) ext_inputchange= *val;
922         else if(event==MOUSEY || event==MOUSEX) ext_mousemove= 1;
923         else if((G.qual & (LR_CTRLKEY|LR_ALTKEY)) && event==F3KEY) {
924                 if(*val) BIF_screendump(0);
925         }
926
927         return event;
928 }
929 unsigned short extern_qread(short *val)
930 {
931         char ascii;
932         return extern_qread_ext(val, &ascii);
933 }
934
935 int blender_test_break(void)
936 {
937         if (!G.background) {
938                 static double ltime= 0;
939                 double curtime= PIL_check_seconds_timer();
940
941                         /* only check for breaks every 10 milliseconds
942                          * if we get called more often.
943                          */
944                 if ((curtime-ltime)>.001) {
945                         ltime= curtime;
946
947                         while(qtest()) {
948                                 short val;
949                                 if (extern_qread(&val) == ESCKEY) {
950                                         G.afbreek= 1;
951                                 }
952                         }
953                 }
954         }
955
956         return (G.afbreek==1);
957 }
958
959 void reset_autosave(void) {
960         window_set_timer(mainwin, U.savetime*60*1000, AUTOSAVE_FILE);
961 }
962
963 /* ************ handlers ************** */
964
965 /* don't know yet how the handlers will evolve, for simplicity
966 i choose for an array with eventcodes, this saves in a file!
967 */
968 void add_screenhandler(bScreen *sc, short eventcode, short val)
969 {
970         short a;
971         
972         // find empty spot
973         for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
974                 if( sc->handler[a]==eventcode ) {
975                         sc->handler[a+1]= val;
976                         break;
977                 }
978                 else if( sc->handler[a]==0) {
979                         sc->handler[a]= eventcode;
980                         sc->handler[a+1]= val;
981                         break;
982                 }
983         }
984         if(a==SCREEN_MAXHANDLER) printf("error; max (4) screen handlers reached!\n");
985 }
986
987 void rem_screenhandler(bScreen *sc, short eventcode)
988 {
989         short a;
990         
991         for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
992                 if( sc->handler[a]==eventcode) {
993                         sc->handler[a]= 0;
994                         break;
995                 }
996         }
997 }
998
999 int has_screenhandler(bScreen *sc, short eventcode)
1000 {
1001         short a;
1002         
1003         for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1004                 if( sc->handler[a]==eventcode) {
1005                         return 1;
1006                 }
1007         }
1008         return 0;
1009 }
1010
1011 static void animated_screen(bScreen *sc, short val)
1012 {
1013         if (U.mixbufsize && (val & TIME_WITH_SEQ_AUDIO)) {
1014                 if(CFRA>=EFRA) {
1015                         CFRA= SFRA;
1016                         audiostream_stop();
1017                         audiostream_start( CFRA );
1018                 }
1019                 else {
1020                         int cfra = audiostream_pos();
1021                         if(cfra <= CFRA) CFRA++;
1022                         else CFRA= cfra;
1023                 }
1024         }
1025         else {
1026                 CFRA++;
1027                 if(CFRA > EFRA) CFRA= SFRA;
1028         }
1029         
1030         update_for_newframe_nodraw(1);
1031         
1032         if(val & TIME_ALL_3D_WIN)
1033                 allqueue(REDRAWVIEW3D, 0);
1034         else if(val & TIME_LEFTMOST_3D_WIN) {
1035                 ScrArea *sa= sc->areabase.first, *samin=NULL;
1036                 int min= 10000;
1037                 for(; sa; sa= sa->next) {
1038                         if(sa->spacetype==SPACE_VIEW3D) {
1039                                 if(sa->winrct.xmin - sa->winrct.ymin < min) {
1040                                         samin= sa;
1041                                         min= sa->winrct.xmin - sa->winrct.ymin;
1042                                 }
1043                         }
1044                 }
1045                 if(samin) scrarea_queue_winredraw(samin);
1046         }
1047         if(val & TIME_ALL_ANIM_WIN) allqueue(REDRAWANIM, 0);
1048         if(val & TIME_ALL_BUTS_WIN) allqueue(REDRAWBUTSALL, 0);
1049         
1050         allqueue(REDRAWTIME, 0);
1051 }
1052
1053 /* because we still have to cope with subloops, this function is called
1054 in viewmove() for example too */
1055
1056 /* returns 1 if something was handled */
1057 /* restricts to frames-per-second setting for frequency of updates */
1058 int do_screenhandlers(bScreen *sc)
1059 {
1060         static double ltime=0.0;
1061         double swaptime, time;
1062         short a, done= 0;
1063         
1064         time = PIL_check_seconds_timer();
1065         swaptime= 1.0/(float)G.scene->r.frs_sec;
1066         
1067         /* only now do the handlers */
1068         if(swaptime < time-ltime || ltime==0.0) {
1069                 
1070                 ltime= time;
1071
1072                 for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1073                         switch(sc->handler[a]) {
1074                                 case SCREEN_HANDLER_ANIM:
1075                                         animated_screen(sc, sc->handler[a+1]);
1076                                         done= 1;
1077                                         break;
1078                                 case SCREEN_HANDLER_PYTHON:
1079                                         done= 1;
1080                                         break;
1081                                 case SCREEN_HANDLER_VERSE:
1082                                         done= 1;
1083                                         break;
1084                         }
1085                 }
1086         }
1087         else if( qtest()==0) PIL_sleep_ms(5);   // 5 milliseconds pause, for idle
1088
1089         /* separate check for if we need to add to afterqueue */
1090         /* is only to keep mainqueue awqke */
1091         for(a=0; a<SCREEN_MAXHANDLER; a+=2) {
1092                 if(sc->handler[a]) {
1093                         ScrArea *sa= sc->areabase.first;
1094                         if(sa->headwin) addafterqueue(sa->headwin, SCREEN_HANDLER, 1);
1095                         else addafterqueue(sa->win, SCREEN_HANDLER, 1);
1096                 }
1097         }
1098         
1099         return done;
1100 }
1101
1102 /* ****** end screen handlers ************ */
1103
1104 static void drawscreen(void)
1105 {
1106         ScrArea *sa;
1107         
1108         mywinset(G.curscreen->mainwin);
1109         myortho2(-0.375, (float)G.curscreen->sizex-0.375, -0.375, (float)G.curscreen->sizey-0.375);
1110         
1111         sa= G.curscreen->areabase.first;
1112         while(sa) {
1113                 drawscredge_area(sa);
1114                 sa= sa->next;
1115         }
1116         
1117         /* this double draw patch seems to be needed for certain sgi's (octane, indigo2) */
1118 #if defined(__sgi) || defined(__sun__) || defined( __sun ) || defined (__sparc) || defined (__sparc__)
1119         glDrawBuffer(GL_FRONT);
1120         
1121         sa= G.curscreen->areabase.first;
1122         while(sa) {
1123                 drawscredge_area(sa);
1124                 sa= sa->next;
1125         }
1126         
1127         glDrawBuffer(GL_BACK);
1128 #endif
1129 }
1130
1131 static void screen_dispatch_events(void) {
1132         int events_remaining= 1;
1133         ScrArea *sa;
1134
1135         window_make_active(mainwin); // added it here instead of screenmain (ton)
1136
1137         while (events_remaining) {
1138                 events_remaining= 0;
1139                                 
1140                 winqueue_break= 0;
1141                 for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1142                                 /* first check header, then rest. Header sometimes has initialization code */
1143                         if (sa->headwin && bwin_qtest(sa->headwin)) {
1144                                 scrarea_dispatch_header_events(sa);
1145                                 events_remaining= 1;
1146                         }
1147                         if (winqueue_break) break;
1148
1149                         if (bwin_qtest(sa->win)) {
1150                                 scrarea_dispatch_events(sa);
1151                                 events_remaining= 1;
1152                         }
1153                         if (winqueue_break) break;
1154                 }
1155
1156                 if (winqueue_break) break;
1157         }
1158
1159         if (dodrawscreen) {
1160                 drawscreen();
1161                 dodrawscreen= 0;
1162         }
1163         
1164         screen_swapbuffers();
1165         do_screenhandlers(G.curscreen);
1166 }
1167
1168 static ScrArea *screen_find_area_for_pt(bScreen *sc, short *mval) 
1169 {
1170         ScrArea *sa;
1171         
1172         /* hotspot area of 1 pixel extra */
1173         
1174         for (sa= sc->areabase.first; sa; sa= sa->next) {
1175                 if( sa->totrct.xmin + 1 < mval[0] )
1176                         if( sa->totrct.ymin + 1 < mval[1] )
1177                                 if( sa->totrct.xmax - 1 > mval[0] )
1178                                         if( sa->totrct.ymax - 1 > mval[1] )
1179                                                 return sa;
1180         }
1181         return NULL;
1182 }
1183
1184 /* ugly yah, will disappear on better event system */
1185 /* is called from interface.c after button events */
1186 static char delayed_undo_name[64];
1187 void screen_delayed_undo_push(char *name)
1188 {
1189         strncpy(delayed_undo_name, name, 63);
1190         mainqenter(UNDOPUSH, 1);
1191 }
1192
1193 void screenmain(void)
1194 {
1195         int has_input= 1;
1196         int firsttime = 1;
1197         int onload_script = 0;
1198
1199         window_make_active(mainwin);
1200         
1201         while (1) {
1202                 unsigned short event;
1203                 short val, towin;
1204                 char ascii;
1205
1206                 flush_extqd_events();
1207                 if (nafterqitems && !qtest()) {
1208                         append_afterqueue();
1209                         event= val= ascii= 0;
1210                 } else {
1211                         event= screen_qread(&val, &ascii);
1212                 }
1213                 
1214                 // window_make_active(mainwin); // (only for inputchange, removed, (ton))
1215
1216                 if (event==INPUTCHANGE) {
1217                         window_make_active(mainwin);
1218                         G.qual= get_qual();
1219                 }
1220                 
1221                         /* If the main window is active, find the current active ScrArea
1222                          * underneath the mouse cursor, updating the headers & cursor for
1223                          * the appropriate internal window if things have changed.
1224                          * 
1225                          * If the main window is not active, deactivate the internal 
1226                          * window.
1227                          */
1228                 if (has_input || g_activearea==NULL || G.curscreen->winakt) {
1229                         ScrArea *newactarea;
1230                         int newactwin;
1231                         short mval[2];
1232
1233                         getmouseco_sc(mval);
1234                         newactarea= screen_find_area_for_pt(G.curscreen, mval);                 
1235
1236                         if (newactarea) {
1237                                 if (BLI_in_rcti(&newactarea->headrct, mval[0], mval[1])) {
1238                                         newactwin= newactarea->headwin;
1239                                 } else {
1240                                         newactwin= newactarea->win;
1241                                 }
1242                         } else {
1243                                 newactwin= 0;
1244                         }
1245
1246                         if (newactarea && (newactarea != g_activearea)) {
1247                                 if (g_activearea) scrarea_queue_headredraw(g_activearea);
1248                                 scrarea_queue_headredraw(newactarea);
1249                                 set_cursor(newactarea->cursor);
1250                                 g_activearea= newactarea;
1251                         }
1252                         /* when you move mouse from header to window, buttons can remain hilited otherwise */
1253                         if(newactwin != G.curscreen->winakt) {
1254                                 if (g_activearea) scrarea_queue_headredraw(g_activearea);
1255                         }
1256                         G.curscreen->winakt= newactwin;
1257                         
1258                         if (G.curscreen->winakt) {
1259                                 areawinset(G.curscreen->winakt);
1260                                 set_cursor(choose_cursor(g_activearea));
1261                         }
1262                 } 
1263                 else {
1264                         if (g_activearea) {
1265                                 scrarea_queue_headredraw(g_activearea);
1266                         }
1267                         g_activearea= NULL;
1268                         G.curscreen->winakt= 0;
1269                 }
1270
1271                 towin= 0;
1272                 if (event==WINCLOSE) {
1273                         exit_usiblender();
1274                 } 
1275                 else if (event==DRAWEDGES) {
1276                         dodrawscreen= 1;
1277                 }
1278                 else if (event==RESHAPE) {
1279                         init_mainwin();
1280                         markdirty_all();
1281                         dodrawscreen= 1;
1282                 }
1283                 else if (event==REDRAW) {
1284                         markdirty_all();
1285                         dodrawscreen= 1;
1286                 }
1287                 else if( event==UNDOPUSH) {
1288                         BIF_undo_push(delayed_undo_name);
1289                 }
1290                 else if (event==AUTOSAVE_FILE) {
1291                         BIF_write_autosave();
1292                 }
1293                 else if (event==LOAD_FILE) {
1294                         BIF_read_file(ext_load_str);
1295                         sound_initialize_sounds();
1296                 }
1297                 else if ((event==ONLOAD_SCRIPT) && BPY_has_onload_script()) {
1298                         /* event queued in setup_app_data() in blender.c, where G.f is checked */
1299                         onload_script = 1;
1300                         firsttime = 1; /* see last 'if' in this function */
1301                 }
1302                 else {
1303                         towin= 1;
1304                 }
1305
1306                 if (!g_activearea) {
1307                         towin= 0;
1308                 }
1309                 else if (event==QKEY) {
1310                         if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
1311                         else {
1312                                 if(val) {
1313                                         if(okee("Quit Blender")) exit_usiblender();
1314                                 }
1315                                 towin= 0;
1316                         }
1317                 }
1318                 else if(ELEM(event, LEFTARROWKEY, RIGHTARROWKEY)) {
1319                         if(textediting==0 && val && (G.qual & LR_CTRLKEY)) {
1320                                 bScreen *sc= (event==LEFTARROWKEY)?G.curscreen->id.prev:G.curscreen->id.next;
1321                                 if(is_allowed_to_change_screen(sc)) setscreen(sc);
1322                                 g_activearea= NULL;
1323                                 towin= 0;
1324                         }
1325                 }
1326                 else if (!G.curscreen->winakt) {
1327                         ScrEdge *actedge;
1328                         short mval[2];
1329
1330                         getmouseco_sc(mval);
1331                         actedge= screen_find_active_scredge(G.curscreen, mval);
1332
1333                         if (actedge) {
1334                                 if (scredge_is_horizontal(actedge)) {
1335                                         set_cursor(CURSOR_Y_MOVE);
1336                                 } else {
1337                                         set_cursor(CURSOR_X_MOVE);
1338                                 }
1339                                 // this does global hotkeys too
1340                                 screen_edge_edit_event(g_activearea, actedge, event, val);
1341                         } else {
1342                                 set_cursor(CURSOR_STD);
1343                         }
1344                         
1345                         towin= 0;
1346                 }
1347                 else if (event==ZKEY) {
1348                         if(val && G.qual==(LR_ALTKEY|LR_SHIFTKEY|LR_CTRLKEY)) {
1349                                 extern void set_debug_swapbuffers_ovveride(bScreen *sc, int mode);
1350
1351                                 int which= pupmenu("Swapbuffers%t|Simple|Debug|DebugSwap|Redraw|Default|KillSwap");
1352                                         
1353                                 switch (which) {
1354                                 case 1: set_debug_swapbuffers_ovveride(G.curscreen, 's'); break;
1355                                 case 2: set_debug_swapbuffers_ovveride(G.curscreen, 'd'); break;
1356                                 case 3: set_debug_swapbuffers_ovveride(G.curscreen, 'f'); break;
1357                                 case 4: set_debug_swapbuffers_ovveride(G.curscreen, 'r'); break;
1358                                 case 5: set_debug_swapbuffers_ovveride(G.curscreen, 0); break;
1359                                 case 6: 
1360                                         if (g_activearea) {
1361                                                 g_activearea->head_swap= 0;
1362                                                 g_activearea->win_swap= 0;
1363                                         }
1364                                         break;
1365                                 }
1366                                 towin= 0;
1367                         }
1368                 }
1369                 else if (event==SPACEKEY) {
1370                         if(val && (G.qual & LR_SHIFTKEY)) {
1371                                 area_fullscreen();
1372                                 g_activearea= NULL;
1373                                 towin= 0;
1374                         }
1375                         else {
1376                                 if((G.obedit && G.obedit->type==OB_FONT && g_activearea->spacetype==SPACE_VIEW3D)||g_activearea->spacetype==SPACE_TEXT||g_activearea->spacetype==SPACE_SCRIPT);
1377                                 else if(G.qual==0) {
1378                                         if(val) toolbox_n();
1379                                         towin= 0;
1380                                 }
1381                         }
1382                 }
1383                 else if(ELEM(event, UPARROWKEY, DOWNARROWKEY)) {
1384                         if(val && (G.qual & LR_CTRLKEY)) {
1385                                 area_fullscreen();
1386                                 g_activearea= NULL;
1387                                 towin= 0;
1388                         }
1389                 }
1390
1391                 if (towin && event) {
1392                         if (blenderqread(event, val))   // the global keys
1393                                 addqueue_ext(G.curscreen->winakt, event, val, ascii);
1394                 }
1395
1396                         /* only process subwindow queue's once the
1397                          * main queue has been emptyied.
1398                          */
1399                 event= qtest();
1400                 if (event==0 || event==EXECUTE) {
1401                         screen_dispatch_events();
1402                 }
1403                 
1404                 if(G.f & G_DEBUG) {
1405                         GLenum error = glGetError();
1406                         if (error)
1407                                 printf("GL error: %s\n", gluErrorString(error));
1408                 }
1409                 /* Bizar hack. The event queue has mutated... */
1410                 if ( (firsttime) && (event == 0) ) {
1411
1412                         if (onload_script) {
1413                                 /* OnLoad scriptlink */
1414                                 BPY_do_pyscript(&G.scene->id, SCRIPT_ONLOAD);
1415                                 onload_script = 0;
1416                         }
1417                         else if (G.fileflags & G_FILE_AUTOPLAY) {
1418                                 // SET AUTOPLAY in G.flags for
1419                                 // other fileloads
1420
1421                                 G.flags |= G_FILE_AUTOPLAY;
1422                                 area_autoplayscreen();
1423
1424                                 // Let The Games Begin
1425                                 // fake a 'p' keypress
1426
1427                                 mainqenter(PKEY, 1);
1428                         } else {
1429                                 extern char datatoc_splash_jpg[];
1430                                 extern int datatoc_splash_jpg_size;
1431
1432                                 //if (! ((G.main->versionfile >= G.version)
1433                                 //       || G.save_over)) {
1434                                         splash((void *)datatoc_splash_jpg,
1435                                                datatoc_splash_jpg_size, NULL);
1436                                 //}
1437                         }
1438                         firsttime = 0;
1439                 }
1440         }
1441 }
1442
1443 #if 0
1444 //#ifdef _WIN32 // FULLSCREEN
1445 void mainwindow_toggle_fullscreen(int fullscreen){
1446         if (fullscreen) U.uiflag |= USER_FLIPFULLSCREEN;
1447         else U.uiflag &= ~USER_FLIPFULLSCREEN;
1448
1449         window_toggle_fullscreen(mainwin, fullscreen);
1450 }
1451 #endif
1452
1453 void mainwindow_raise(void) {
1454         window_raise(mainwin);
1455 }
1456
1457 void mainwindow_make_active(void) {
1458         window_make_active(mainwin);
1459 }
1460
1461 void mainwindow_close(void) {
1462         window_destroy(mainwin);
1463         mainwin= NULL;
1464 }
1465
1466 void mainwindow_set_filename_to_title(char *filename) {
1467         char str[FILE_MAXDIR + FILE_MAXFILE];
1468         char dir[FILE_MAXDIR];
1469         char file[FILE_MAXFILE];
1470
1471         BLI_split_dirfile(filename, dir, file);
1472
1473         if(BLI_streq(file, ".B.blend") || filename[0] =='\0')
1474                 sprintf(str, "Blender");
1475         else
1476                 sprintf(str, "Blender [%s]", filename);
1477
1478         window_set_title(mainwin, str);
1479 }
1480
1481 /* *********  AREAS  ************* */
1482
1483 void setprefsize(int stax, int stay, int sizx, int sizy)
1484 {
1485         int scrwidth, scrheight;
1486         
1487         winlay_get_screensize(&scrwidth, &scrheight);
1488                 
1489         if(stax<0) stax= 0;
1490         if(stay<0) stay= 0;
1491         if(sizx<320) sizx= 320;
1492         if(sizy<256) sizy= 256;
1493
1494         if(stax+sizx>scrwidth) {
1495                 fprintf(stderr," width prob \n");
1496                 sizx= scrwidth-stax;
1497                 }
1498
1499         if(stay+sizy>scrheight) {
1500                 fprintf(stderr," height prob \n");
1501                 sizy= scrheight-stay;
1502                 }
1503
1504 /* #ifdef __APPLE__ */
1505 /*      if(stay+sizy>scrheight-22) sizy= scrheight-22-stay;     // 22 = topbar  */
1506 /* #endif*/
1507
1508         if(sizx<320 || sizy<256) {
1509                 printf("ERROR: illegal prefsize\n");
1510                 return;
1511         }
1512         
1513         prefstax= stax;
1514         prefstay= stay;
1515         prefsizx= sizx;
1516         prefsizy= sizy;
1517
1518         start_maximized= 0;
1519 }
1520
1521
1522 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
1523 {
1524         ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
1525         sv->vec.x= x;
1526         sv->vec.y= y;
1527         
1528         BLI_addtail(&sc->vertbase, sv);
1529         return sv;
1530 }
1531
1532 static void sortscrvert(ScrVert **v1, ScrVert **v2)
1533 {
1534         ScrVert *tmp;
1535         
1536         if (*v1 > *v2) {
1537                 tmp= *v1;
1538                 *v1= *v2;
1539                 *v2= tmp;       
1540         }
1541 }
1542
1543 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1544 {
1545         ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
1546
1547         sortscrvert(&v1, &v2);
1548         se->v1= v1;
1549         se->v2= v2;
1550         
1551         BLI_addtail(&sc->edgebase, se);
1552         return se;
1553 }
1554
1555 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
1556 {
1557         ScrEdge *se;
1558
1559         sortscrvert(&v1, &v2);
1560         for (se= sc->edgebase.first; se; se= se->next)
1561                 if(se->v1==v1 && se->v2==v2)
1562                         return se;
1563
1564         return NULL;
1565 }
1566
1567 static void removedouble_scrverts(void)
1568 {
1569         ScrVert *v1, *verg;
1570         ScrEdge *se;
1571         ScrArea *sa;
1572         
1573         verg= G.curscreen->vertbase.first;
1574         while(verg) {
1575                 if(verg->newv==0) {     /* !!! */
1576                         v1= verg->next;
1577                         while(v1) {
1578                                 if(v1->newv==0) {       /* !?! */
1579                                         if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
1580                                                 /* printf("doublevert\n"); */
1581                                                 v1->newv= verg;
1582                                         }
1583                                 }
1584                                 v1= v1->next;
1585                         }
1586                 }
1587                 verg= verg->next;
1588         }
1589         
1590         /* replace pointers in edges and faces */
1591         se= G.curscreen->edgebase.first;
1592         while(se) {
1593                 if(se->v1->newv) se->v1= se->v1->newv;
1594                 if(se->v2->newv) se->v2= se->v2->newv;
1595                 /* edges changed: so.... */
1596                 sortscrvert(&(se->v1), &(se->v2));
1597                 se= se->next;
1598         }
1599         sa= G.curscreen->areabase.first;
1600         while(sa) {
1601                 if(sa->v1->newv) sa->v1= sa->v1->newv;
1602                 if(sa->v2->newv) sa->v2= sa->v2->newv;
1603                 if(sa->v3->newv) sa->v3= sa->v3->newv;
1604                 if(sa->v4->newv) sa->v4= sa->v4->newv;
1605                 sa= sa->next;
1606         }
1607         
1608         /* remove */
1609         verg= G.curscreen->vertbase.first;
1610         while(verg) {
1611                 v1= verg->next;
1612                 if(verg->newv) {
1613                         BLI_remlink(&G.curscreen->vertbase, verg);
1614                         MEM_freeN(verg);
1615                 }
1616                 verg= v1;
1617         }
1618         
1619 }
1620
1621 static void removenotused_scrverts(void)
1622 {
1623         ScrVert *sv, *svn;
1624         ScrEdge *se;
1625
1626         /* we assume edges are ok */
1627         
1628         se= G.curscreen->edgebase.first;
1629         while(se) {
1630                 se->v1->flag= 1;
1631                 se->v2->flag= 1;
1632                 se= se->next;
1633         }
1634         
1635         sv= G.curscreen->vertbase.first;
1636         while(sv) {
1637                 svn= sv->next;
1638                 if(sv->flag==0) {
1639                         BLI_remlink(&G.curscreen->vertbase, sv);
1640                         MEM_freeN(sv);
1641                 }
1642                 else sv->flag= 0;
1643                 sv= svn;
1644         }
1645 }
1646
1647 static void removedouble_scredges(void)
1648 {
1649         ScrEdge *verg, *se, *sn;
1650         
1651         /* compare */
1652         verg= G.curscreen->edgebase.first;
1653         while(verg) {
1654                 se= verg->next;
1655                 while(se) {
1656                         sn= se->next;
1657                         if(verg->v1==se->v1 && verg->v2==se->v2) {
1658                                 BLI_remlink(&G.curscreen->edgebase, se);
1659                                 MEM_freeN(se);
1660                         }
1661                         se= sn;
1662                 }
1663                 verg= verg->next;
1664         }
1665 }
1666
1667 static void removenotused_scredges(void)
1668 {
1669         ScrEdge *se, *sen;
1670         ScrArea *sa;
1671         int a=0;
1672         
1673         /* sets flags when edge is used in area */
1674         sa= G.curscreen->areabase.first;
1675         while(sa) {
1676                 se= screen_findedge(G.curscreen, sa->v1, sa->v2);
1677                 if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
1678                 else se->flag= 1;
1679                 se= screen_findedge(G.curscreen, sa->v2, sa->v3);
1680                 if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
1681                 else se->flag= 1;
1682                 se= screen_findedge(G.curscreen, sa->v3, sa->v4);
1683                 if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
1684                 else se->flag= 1;
1685                 se= screen_findedge(G.curscreen, sa->v4, sa->v1);
1686                 if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
1687                 else se->flag= 1;
1688                 sa= sa->next;
1689                 a++;
1690         }
1691         se= G.curscreen->edgebase.first;
1692         while(se) {
1693                 sen= se->next;
1694                 if(se->flag==0) {
1695                         BLI_remlink(&G.curscreen->edgebase, se);
1696                         MEM_freeN(se);
1697                 }
1698                 else se->flag= 0;
1699                 se= sen;
1700         }
1701 }
1702
1703 void calc_arearcts(ScrArea *sa)
1704 {
1705
1706         if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1;
1707         else sa->totrct.xmin= sa->v1->vec.x;
1708         if(sa->v4->vec.x<G.curscreen->sizex-1) sa->totrct.xmax= sa->v4->vec.x-1;
1709         else sa->totrct.xmax= sa->v4->vec.x;
1710         
1711         if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1;
1712         else sa->totrct.ymin= sa->v1->vec.y;
1713         if(sa->v2->vec.y<G.curscreen->sizey-1) sa->totrct.ymax= sa->v2->vec.y-1;
1714         else sa->totrct.ymax= sa->v2->vec.y;
1715         
1716         sa->winrct= sa->totrct;
1717         sa->headrct= sa->totrct;
1718         if(sa->headertype) {
1719                 if(sa->headertype==HEADERDOWN) {
1720                         sa->headrct.ymax= sa->headrct.ymin+HEADERY;
1721                         sa->winrct.ymin= sa->headrct.ymax+1;
1722                 }
1723                 else if(sa->headertype==HEADERTOP) {
1724                         sa->headrct.ymin= sa->headrct.ymax-HEADERY;
1725                         sa->winrct.ymax= sa->headrct.ymin-1;
1726                 }
1727         }
1728         else {
1729                 sa->headrct.ymax= sa->headrct.ymin;
1730         }
1731         if(sa->winrct.ymin>sa->winrct.ymax) sa->winrct.ymin= sa->winrct.ymax;
1732         
1733         /* for speedup */
1734         sa->winx= sa->winrct.xmax-sa->winrct.xmin+1;
1735         sa->winy= sa->winrct.ymax-sa->winrct.ymin+1;
1736 }
1737
1738 static void openheadwin(ScrArea *sa)
1739 {
1740         sa->headwin= myswinopen(G.curscreen->mainwin,
1741                 sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1742
1743         glMatrixMode(GL_MODELVIEW);
1744         
1745         areawinar[sa->headwin]= sa;     /* oterwise addqueue does not work */
1746         addqueue(sa->headwin, CHANGED, 1);
1747 }
1748
1749 static void openareawin(ScrArea *sa)
1750 {
1751         sa->win= myswinopen(G.curscreen->mainwin, 
1752                 sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1753
1754         areawinar[sa->win]= sa; /* otherwise addqueue does not work */
1755         addqueue(sa->win, CHANGED, 1);
1756 }
1757
1758 static void closeheadwin(ScrArea *sa)
1759 {
1760         if(sa->headwin) mywinclose(sa->headwin);
1761         sa->headwin= 0;
1762 }
1763
1764 static void closeareawin(ScrArea *sa)
1765 {
1766         uiFreeBlocksWin(&sa->uiblocks, sa->win);
1767         
1768         if(sa->win) mywinclose(sa->win);
1769         sa->win= 0;
1770 }
1771
1772 static void del_area(ScrArea *sa)
1773 {
1774         closeareawin(sa);
1775         closeheadwin(sa);
1776
1777         freespacelist(&sa->spacedata);
1778         
1779         uiFreeBlocks(&sa->uiblocks);
1780         uiFreePanels(&sa->panels);
1781         
1782         if(sa==curarea) curarea= 0;
1783         if(sa==g_activearea) g_activearea= 0;
1784 }
1785
1786 /* sa2 to sa1 */
1787 static void copy_areadata(ScrArea *sa1, ScrArea *sa2)
1788 {
1789         Panel *pa1, *pa2, *patab;
1790         ScriptLink *slink1 = &sa1->scriptlink, *slink2 = &sa2->scriptlink;
1791
1792         sa1->headertype= sa2->headertype;
1793         sa1->spacetype= sa2->spacetype;
1794         Mat4CpyMat4(sa1->winmat, sa2->winmat);
1795
1796         freespacelist(&sa1->spacedata);
1797         duplicatespacelist(sa1, &sa1->spacedata, &sa2->spacedata);
1798
1799         BLI_freelistN(&sa1->panels);
1800         duplicatelist(&sa1->panels, &sa2->panels);
1801
1802         /* space handler script links */
1803         if (slink1->totscript) {
1804                 MEM_freeN(slink1->scripts);
1805                 MEM_freeN(slink1->flag);
1806                 slink1->totscript = 0;
1807         }
1808         if (slink2->totscript) {
1809                 slink1->scripts = MEM_dupallocN(slink2->scripts);
1810                 slink1->flag = MEM_dupallocN(slink2->flag);
1811                 slink1->totscript = slink2->totscript;
1812         }
1813
1814         /* copy pointers */
1815         pa1= sa1->panels.first;
1816         while(pa1) {
1817                 
1818                 patab= sa1->panels.first;
1819                 pa2= sa2->panels.first;
1820                 while(patab) {
1821                         if( pa1->paneltab == pa2) {
1822                                 pa1->paneltab = patab;
1823                                 break;
1824                         }
1825                         patab= patab->next;
1826                         pa2= pa2->next;
1827                 }
1828                 pa1= pa1->next;
1829         }
1830 }
1831
1832 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
1833 {
1834         ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
1835         sa->cursor= CURSOR_STD;
1836         sa->v1= v1;
1837         sa->v2= v2;
1838         sa->v3= v3;
1839         sa->v4= v4;
1840         sa->headertype= headertype;
1841         sa->spacetype= spacetype;
1842
1843         calc_arearcts(sa);
1844
1845         if (sa->headertype) openheadwin(sa);
1846         openareawin(sa);
1847
1848         BLI_addtail(&sc->areabase, sa);
1849         return sa;
1850 }
1851
1852 static int rcti_eq(rcti *a, rcti *b) {
1853         return ((a->xmin==b->xmin && a->xmax==b->xmax) &&
1854                         (a->ymin==b->ymin && a->ymax==b->ymax));
1855 }
1856
1857 static void testareas(void)
1858 {
1859         ScrArea *sa, *next;
1860
1861         /* test for header, if removed, or moved */
1862         /* test for window, if removed, or moved */
1863         
1864         sa= G.curscreen->areabase.first;
1865         while(sa) {
1866                 rcti oldhr= sa->headrct;
1867                 rcti oldwr= sa->winrct;
1868                 
1869                 next= sa->next;
1870                 
1871                 calc_arearcts(sa);
1872                 
1873                 /* ilegally scaled down area.... */
1874                 if(sa->totrct.xmin>=sa->totrct.xmax || sa->totrct.ymin>=sa->totrct.ymax) {
1875                         del_area(sa);
1876                         BLI_remlink(&G.curscreen->areabase, sa);
1877                         MEM_freeN(sa);
1878                         printf("Warning, removed zero sized window from screen %s\n", G.curscreen->id.name+2);
1879                 }
1880                 else {
1881                                 /* test header */
1882                         if (sa->headwin) {
1883                                 if (!rcti_eq(&oldhr, &sa->headrct)) {
1884                                         mywinposition(sa->headwin, sa->headrct.xmin, sa->headrct.xmax, sa->headrct.ymin, sa->headrct.ymax);
1885                                         addqueue(sa->headwin, CHANGED, 1);
1886                                 }
1887                                         
1888                                 if(sa->headbutlen<sa->winx) {
1889                                         sa->headbutofs= 0;
1890                                         addqueue(sa->headwin, CHANGED, 1);
1891                                 }
1892                                 else if(sa->headbutofs+sa->winx > sa->headbutlen) {
1893                                         sa->headbutofs= sa->headbutlen-sa->winx;
1894                                         addqueue(sa->headwin, CHANGED, 1);
1895                                 }
1896                         }
1897
1898                         if (!rcti_eq(&oldwr, &sa->winrct)) {
1899                                 mywinposition(sa->win, sa->winrct.xmin, sa->winrct.xmax, sa->winrct.ymin, sa->winrct.ymax);
1900                                 addqueue(sa->win, CHANGED, 1);
1901                         }
1902                 }
1903                 sa= next;
1904         }
1905         
1906                 /* remake global windowarray */
1907         memset(areawinar, 0, sizeof(void *)*MAXWIN);
1908         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
1909                 areawinar[sa->headwin]= sa;
1910                 areawinar[sa->win]= sa;
1911         }
1912         
1913                 /* test if winakt is OK */      
1914         if( areawinar[G.curscreen->winakt]==0) G.curscreen->winakt= 0;
1915 }
1916
1917 static ScrArea *test_edge_area(ScrArea *sa, ScrEdge *se)
1918 {
1919         /* test if edge is in area, if not, 
1920            then find an area that has it */
1921   
1922         ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
1923         
1924         if(sa) {
1925                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1926                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1927                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1928                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1929         }
1930         if(se1!=se && se2!=se && se3!=se && se4!=se) {
1931                 
1932                 sa= G.curscreen->areabase.first;
1933                 while(sa) {
1934                         /* a bit optimise? */
1935                         if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
1936                                 se1= screen_findedge(G.curscreen, sa->v1, sa->v2);
1937                                 se2= screen_findedge(G.curscreen, sa->v2, sa->v3);
1938                                 se3= screen_findedge(G.curscreen, sa->v3, sa->v4);
1939                                 se4= screen_findedge(G.curscreen, sa->v4, sa->v1);
1940                                 if(se1==se || se2==se || se3==se || se4==se) return sa;
1941                         }
1942                         sa= sa->next;
1943                 }
1944         }
1945
1946         return sa;      /* is null when not find */
1947 }
1948
1949 ScrArea *closest_bigger_area(void)
1950 {
1951         ScrArea *sa, *big=0;
1952         float cent[3], vec[3],len, len1, len2, len3, dist=1000;
1953         short mval[2];
1954         
1955         getmouseco_sc(mval);
1956         
1957         cent[0]= mval[0];
1958         cent[1]= mval[1];
1959         cent[2]= vec[2]= 0;
1960
1961         sa= G.curscreen->areabase.first;
1962         while(sa) {
1963                 if(sa!=curarea) {
1964                         if(sa->winy>=curarea->winy) {
1965                         
1966                                 /* mimimum of the 4 corners */
1967                                 vec[0]= sa->v1->vec.x; vec[1]= sa->v1->vec.y;
1968                                 len= VecLenf(vec, cent);
1969                                 vec[0]= sa->v2->vec.x; vec[1]= sa->v2->vec.y;
1970                                 len1= VecLenf(vec, cent);
1971                                 vec[0]= sa->v3->vec.x; vec[1]= sa->v3->vec.y;
1972                                 len2= VecLenf(vec, cent);
1973                                 vec[0]= sa->v4->vec.x; vec[1]= sa->v4->vec.y;
1974                                 len3= VecLenf(vec, cent);
1975                                 
1976                                 len= MIN4(len, len1, len2, len3);
1977                                 
1978                                 /* plus centre */
1979                                 vec[0]= (sa->v2->vec.x+sa->v3->vec.x)/2;
1980                                 vec[1]= (sa->v1->vec.y+sa->v2->vec.y)/2;
1981
1982                                 len+= 0.5*VecLenf(vec, cent);
1983                                 
1984                                 /* min size */
1985                                 len-= sa->winy+sa->winx;
1986                                 
1987                                 if(len<dist) {
1988                                         dist= len;
1989                                         big= sa;
1990                                 }
1991                         }
1992                 }
1993                 sa= sa->next;
1994         }
1995         
1996         if(big) return big;
1997         else return curarea;
1998 }
1999
2000 /* ************ SCREEN MANAGEMENT ************** */
2001
2002 static int statechanged= 0;
2003 void BIF_wait_for_statechange(void)
2004 {
2005         if (!statechanged) {
2006                         /* Safety, don't wait more than 0.1 seconds */
2007                 double stime= PIL_check_seconds_timer();
2008                 while (!statechanged) {
2009                         winlay_process_events(1);
2010                         if ((PIL_check_seconds_timer()-stime)>0.1) break;
2011                 }
2012                 statechanged= 0;
2013         }
2014         else PIL_sleep_ms(3);   /* statechanged can be set '1' while holding mousebutton, causing locks */
2015
2016 }
2017 void getmouse(short *mval)
2018 {
2019         winlay_process_events(0);
2020         window_get_mouse(mainwin, mval);
2021 }
2022 short get_qual(void)
2023 {
2024         winlay_process_events(0);
2025         return window_get_qual(mainwin);
2026 }
2027 short get_mbut(void)
2028 {
2029         winlay_process_events(0);
2030         return window_get_mbut(mainwin);
2031 }
2032
2033 void add_to_mainqueue(Window *win, void *user_data, short evt, short val, char ascii)
2034 {
2035
2036         statechanged= 1;
2037
2038         /*  accept the extended ascii set (ton) */
2039         if( !val || ascii<32 ) {
2040                 ascii= '\0';
2041         }
2042
2043         mainqenter_ext(evt, val, ascii);
2044 }
2045
2046 /* ScrVert ordering in a ScrArea:
2047
2048 2---------3
2049 |         |
2050 |         |
2051 1---------4
2052   
2053 */
2054
2055 static bScreen *addscreen(char *name)           /* use setprefsize() if you want something else than a full windpw */
2056 {
2057         /* this function sets variabele G.curscreen,
2058          * that global is about used everywhere!
2059          */
2060         bScreen *sc;
2061         ScrVert *sv1, *sv2, *sv3, *sv4;
2062         short startx, starty, endx, endy;       
2063         
2064         sc= G.curscreen= alloc_libblock(&G.main->screen, ID_SCR, name);
2065
2066         if (!prefsizx) {
2067                 prefstax= 0;
2068                 prefstay= 0;
2069                 
2070                 winlay_get_screensize(&prefsizx, &prefsizy);
2071         }
2072
2073         startx= prefstax;
2074         starty= prefstay;
2075         endx= prefstax+prefsizx-1;
2076         endy= prefstay+prefsizy-1;
2077
2078         sc->startx= startx;     sc->starty= starty;
2079         sc->endx= endx; sc->endy= endy;
2080         sc->sizex= sc->endx-sc->startx+1;
2081         sc->sizey= sc->endy-sc->starty+1;
2082         
2083         sc->scene= G.scene;
2084         
2085         if (!mainwin) {
2086 #if 0
2087 //#ifdef _WIN32 // FULLSCREEN
2088                 if (G.windowstate == G_WINDOWSTATE_FULLSCREEN)
2089                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, G_WINDOWSTATE_FULLSCREEN);
2090                 else
2091                         mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
2092 #else
2093                 mainwin= window_open("Blender", sc->startx, sc->starty, sc->sizex, sc->sizey, start_maximized);
2094 #endif
2095                 
2096                 if (!mainwin) {
2097                         printf("ERROR: Unable to open Blender window\n");
2098                         exit(1);
2099                 }
2100                 
2101                 window_set_handler(mainwin, add_to_mainqueue, NULL);
2102                 init_mainwin();
2103                 mywinset(1);
2104         
2105                 /* for visual speed, but still needed? */
2106                 glClearColor(.55, .55, .55, 0.0);
2107                 glClear(GL_COLOR_BUFFER_BIT);
2108                 window_swap_buffers(mainwin);
2109                 
2110                 warp_pointer(sc->sizex/2,  sc->sizey/2);
2111                 
2112                 mainqenter(REDRAW, 1);
2113         }
2114
2115         sc->mainwin= 1;
2116         
2117         sv1= screen_addvert(sc, 0, 0);
2118         sv2= screen_addvert(sc, 0, sc->endy-sc->starty);
2119         sv3= screen_addvert(sc, sc->sizex-1, sc->sizey-1);
2120         sv4= screen_addvert(sc, sc->sizex-1, 0);
2121         
2122         screen_addedge(sc, sv1, sv2);
2123         screen_addedge(sc, sv2, sv3);
2124         screen_addedge(sc, sv3, sv4);
2125         screen_addedge(sc, sv4, sv1);
2126
2127         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
2128         
2129         G.curscreen= sc;
2130
2131         return sc;
2132 }
2133
2134 void setscreen(bScreen *sc)
2135 {
2136         bScreen *sc1;
2137         ScrArea *sa;
2138         short mval[2];
2139         
2140         if(sc->full) {                          /* find associated full */
2141                 sc1= G.main->screen.first;
2142                 while(sc1) {
2143                         sa= sc1->areabase.first;
2144                         if(sa->full==sc) {
2145                                 sc= sc1;
2146                                 break;
2147                         }
2148                         sc1= sc1->id.next;
2149                 }
2150                 if(sc1==0) printf("setscreen error\n");
2151         }
2152
2153         /* de-activate G.curscreen */
2154         if (G.curscreen && G.curscreen != sc) {
2155                 sa= G.curscreen->areabase.first;
2156                 while(sa) {
2157                         if(sa->win) mywinclose(sa->win);
2158                         sa->win= 0;
2159                         if(sa->headwin) mywinclose(sa->headwin);
2160                         sa->headwin= 0;
2161                         
2162                         uiFreeBlocks(&sa->uiblocks);
2163                         
2164                         sa= sa->next;
2165                 }               
2166         }
2167         else if(G.curscreen) markdirty_all();   /* at least redraw */
2168
2169         if (G.curscreen != sc) {
2170                 mywinset(sc->mainwin);
2171         }
2172         
2173         G.curscreen= sc;
2174
2175         for (sa= sc->areabase.first; sa; sa= sa->next) {
2176                         /* XXX, fixme zr */
2177 /*              if (sa->win || sa->headwin) */
2178 /*                      printf("error in setscreen (win): %d, %d\n", sa->win, sa->headwin); */
2179                 if (!sa->win)
2180                         openareawin(sa);
2181                 if (!sa->headwin && sa->headertype)
2182                         openheadwin(sa);
2183         }
2184
2185         /* recalculate winakt */
2186         getmouseco_sc(mval);
2187
2188         test_scale_screen(sc);
2189         testareas();
2190         
2191         for(sa= sc->areabase.first; sa; sa= sa->next) {
2192                 SpaceLink *sl;
2193
2194                 for(sl= sa->spacedata.first; sl; sl= sl->next) {
2195                         sl->area= sa;
2196
2197                         if(sl->spacetype==SPACE_OOPS) {
2198                                 SpaceOops *soops= (SpaceOops *) sl;
2199
2200                                 /* patch for old files */
2201                                 if(soops->v2d.cur.xmin==soops->v2d.cur.xmax) {
2202                                         init_v2d_oops(sa, soops);
2203                                 }
2204                         }
2205                         else if(sl->spacetype==SPACE_BUTS) {
2206                                 SpaceButs *sbuts= (SpaceButs *)sl;
2207                                 sbuts->re_align= 1;             // force an align call, maybe new panels were added, also for after file reading
2208                         }
2209                 }
2210                 
2211                 sa->cursor= CURSOR_STD;
2212         }
2213         
2214         G.scene= sc->scene;
2215         countall();
2216         
2217         G.curscreen->winakt= 0;
2218         curarea= sc->areabase.first;
2219         
2220         mainqenter(DRAWEDGES, 1);
2221         dodrawscreen= 1;                /* patch! even gets lost,,,? */
2222
2223         winqueue_break= 1;              /* means leave queue everywhere */
2224 }
2225
2226 static void splitarea(ScrArea *sa, char dir, float fac);
2227
2228 void area_fullscreen(void)      /* with curarea */
2229 {
2230         /* this function toggles: if area is full then the parent will be restored */
2231         bScreen *sc, *oldscreen;
2232         ScrArea *newa, *old;
2233         short headertype, fulltype;
2234         
2235         if(curarea->full) {
2236                 sc= curarea->full;      /* the old screen */
2237                 fulltype = sc->full;
2238
2239                 // refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
2240                 // is set
2241
2242                 if (fulltype != SCREENAUTOPLAY || (G.flags & G_FILE_AUTOPLAY) == 0) {
2243                         sc->full= 0;
2244                 
2245                         /* find old area */
2246                         old= sc->areabase.first;
2247                         while(old) {
2248                                 if(old->full) break;
2249                                 old= old->next;
2250                         }
2251                         if(old==0) {error("something wrong in areafullscreen"); return;}
2252                 
2253                         if (fulltype == SCREENAUTOPLAY) {
2254                                 // in autoplay screens the headers are disabled by 
2255                                 // default. So use the old headertype instead
2256                                 headertype = old->headertype;
2257                         } else {
2258                                 // normal fullscreen. Use current headertype
2259                                 headertype = curarea->headertype;
2260                         }
2261
2262                         copy_areadata(old, curarea);
2263                         old->headertype = headertype;
2264
2265                         old->full= 0;
2266                 
2267                         unlink_screen(G.curscreen);
2268                         free_libblock(&G.main->screen, G.curscreen);
2269                         G.curscreen= NULL;
2270
2271                         setscreen(sc);
2272                 }
2273                 
2274         }
2275         else {
2276                 /* is there only 1 area? */
2277                 if(G.curscreen->areabase.first==G.curscreen->areabase.last) return;
2278                 if(curarea->spacetype==SPACE_INFO) return;
2279                 
2280                 G.curscreen->full = SCREENFULL;
2281                 
2282                 old= curarea;           
2283                 oldscreen= G.curscreen;
2284                 sc= addscreen("temp");          /* this sets G.curscreen */
2285
2286                 splitarea( (ScrArea *)sc->areabase.first, 'h', 0.99);
2287                 newa= sc->areabase.first;
2288                 newspace(newa->next, SPACE_INFO);
2289                 
2290                 curarea= old;
2291                 G.curscreen= oldscreen; /* needed because of setscreen */
2292                 
2293                 /* copy area */
2294                 copy_areadata(newa, curarea);
2295                 
2296                 curarea->full= oldscreen;
2297                 newa->full= oldscreen;
2298                 newa->next->full= oldscreen;
2299                 
2300                 setscreen(sc);
2301                 wich_cursor(newa);
2302         }
2303 }
2304
2305 static void area_autoplayscreen(void)
2306 {
2307         bScreen *sc, *oldscreen;
2308         ScrArea *newa, *old, *sa;
2309         
2310         if (curarea->full) {
2311                 area_fullscreen();
2312         }
2313
2314         if (curarea->full == NULL) { 
2315                 sa = G.curscreen->areabase.first;
2316                 while (sa) {
2317                         if (sa->spacetype == SPACE_VIEW3D) {
2318                                 break;
2319                         }
2320                         sa= sa->next;
2321                 }
2322
2323                 if (sa) {
2324                         areawinset(sa->win);
2325                         G.curscreen->full = SCREENAUTOPLAY;
2326                         
2327                         old= curarea;           
2328                         oldscreen= G.curscreen;
2329                         sc= addscreen("temp");          /* this sets G.curscreen */
2330         
2331                         newa= sc->areabase.first;
2332                         
2333                         curarea= old;
2334                         G.curscreen= oldscreen; /* because of setscreen */
2335                         
2336                         /* copy area settings */
2337                         copy_areadata(newa, curarea);
2338                         newa->headertype= 0;
2339                         
2340                         curarea->full= oldscreen;
2341                         newa->full= oldscreen;
2342         
2343                         setscreen(sc);
2344                         wich_cursor(newa);
2345                 }
2346         }
2347 }
2348
2349 static void copy_screen(bScreen *to, bScreen *from)
2350 {
2351         ScrVert *s1, *s2;
2352         ScrEdge *se;
2353         ScrArea *sa, *saf;
2354
2355         /* free 'to' */
2356         free_screen(to);
2357         winqueue_break= 1;      /* leave queues everywhere */
2358         
2359         duplicatelist(&to->vertbase, &from->vertbase);
2360         duplicatelist(&to->edgebase, &from->edgebase);
2361         duplicatelist(&to->areabase, &from->areabase);
2362         
2363         s1= from->vertbase.first;
2364         s2= to->vertbase.first;
2365         while(s1) {
2366                 s1->newv= s2;
2367                 s2= s2->next;
2368                 s1= s1->next;
2369         }
2370         se= to->edgebase.first;
2371         while(se) {
2372                 se->v1= se->v1->newv;
2373                 se->v2= se->v2->newv;
2374                 sortscrvert(&(se->v1), &(se->v2));
2375                 se= se->next;
2376         }
2377
2378         sa= to->areabase.first;
2379         saf= from->areabase.first;
2380         while(sa) {
2381                 sa->v1= sa->v1->newv;
2382                 sa->v2= sa->v2->newv;
2383                 sa->v3= sa->v3->newv;
2384                 sa->v4= sa->v4->newv;
2385                 sa->win= 0;
2386                 sa->headwin= 0;
2387                 
2388                 sa->spacedata.first= sa->spacedata.last= NULL;
2389                 sa->uiblocks.first= sa->uiblocks.last= NULL;
2390                 sa->panels.first= sa->panels.last= NULL;
2391                 copy_areadata(sa, saf);
2392                 
2393                 sa= sa->next;
2394                 saf= saf->next;
2395         }
2396         
2397         /* put at zero (needed?) */
2398         s1= from->vertbase.first;
2399         while(s1) {
2400                 s1->newv= 0;
2401                 s1= s1->next;
2402         }
2403 }
2404
2405 void duplicate_screen(void)
2406 {
2407         bScreen *sc, *oldscreen;
2408         
2409         if(G.curscreen->full != SCREENNORMAL) return;
2410         
2411         /* make new screen: */
2412
2413         oldscreen= G.curscreen;
2414         sc= addscreen(oldscreen->id.name+2);    /* this sets G.curscreen */
2415         copy_screen(sc, oldscreen);
2416
2417         G.curscreen= oldscreen;
2418         setscreen(sc);
2419
2420 }
2421
2422
2423 /* ************ END SCREEN MANAGEMENT ************** */
2424 /* ************  JOIN/SPLIT/MOVE ************** */
2425
2426 typedef struct point{
2427         float x,y;
2428 }_point;
2429
2430 /* draw vertical shape visualising future joining (left as well
2431  * right direction of future joining) */
2432 static void draw_horizontal_join_shape(ScrArea *sa, char dir)
2433 {
2434         _point points[10];
2435         short i;
2436         float w, h;
2437         float width = sa->v3->vec.x - sa->v1->vec.x;
2438         float height = sa->v3->vec.y - sa->v1->vec.y;
2439
2440         if(height<width) {
2441                 h = height/8;
2442                 w = height/4;
2443         }
2444         else {
2445                 h = width/8;
2446                 w = width/4;
2447         }
2448
2449         points[0].x = sa->v1->vec.x;
2450         points[0].y = sa->v1->vec.y + height/2;
2451
2452         points[1].x = sa->v1->vec.x;
2453         points[1].y = sa->v1->vec.y;
2454
2455         points[2].x = sa->v4->vec.x - w;
2456         points[2].y = sa->v4->vec.y;
2457
2458         points[3].x = sa->v4->vec.x - w;
2459         points[3].y = sa->v4->vec.y + height/2 - 2*h;
2460
2461         points[4].x = sa->v4->vec.x - 2*w;
2462         points[4].y = sa->v4->vec.y + height/2;
2463
2464         points[5].x = sa->v4->vec.x - w;
2465         points[5].y = sa->v4->vec.y + height/2 + 2*h;
2466
2467         points[6].x = sa->v3->vec.x - w;
2468         points[6].y = sa->v3->vec.y;
2469
2470         points[7].x = sa->v2->vec.x;
2471         points[7].y = sa->v2->vec.y;
2472
2473         points[8].x = sa->v4->vec.x;
2474         points[8].y = sa->v4->vec.y + height/2 - h;
2475
2476         points[9].x = sa->v4->vec.x;
2477         points[9].y = sa->v4->vec.y + height/2 + h;
2478
2479         if(dir=='l') {
2480                 /* when direction is left, then we flip direction of arrow */
2481                 float cx = sa->v1->vec.x + width;
2482                 for(i=0;i<10;i++) {
2483                         points[i].x -= cx;
2484                         points[i].x = -points[i].x;
2485                         points[i].x += sa->v1->vec.x;
2486                 }
2487         }
2488
2489         glBegin(GL_POLYGON);
2490         for(i=0;i<8;i++)
2491                 glVertex2f(points[i].x, points[i].y);
2492         glEnd();
2493
2494         glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
2495         glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
2496 }
2497
2498 /* draw vertical shape visualising future joining (up/down direction) */
2499 static void draw_vertical_join_shape(ScrArea *sa, char dir)
2500 {
2501         _point points[10];
2502         short i;
2503         float w, h;
2504         float width = sa->v3->vec.x - sa->v1->vec.x;
2505         float height = sa->v3->vec.y - sa->v1->vec.y;
2506
2507         if(height<width) {
2508                 h = height/4;
2509                 w = height/8;
2510         }
2511         else {
2512                 h = width/4;
2513                 w = width/8;
2514         }
2515
2516         points[0].x = sa->v1->vec.x + width/2;
2517         points[0].y = sa->v3->vec.y;
2518
2519         points[1].x = sa->v2->vec.x;
2520         points[1].y = sa->v2->vec.y;
2521
2522         points[2].x = sa->v1->vec.x;
2523         points[2].y = sa->v1->vec.y + h;
2524
2525         points[3].x = sa->v1->vec.x + width/2 - 2*w;
2526         points[3].y = sa->v1->vec.y + h;
2527
2528         points[4].x = sa->v1->vec.x + width/2;
2529         points[4].y = sa->v1->vec.y + 2*h;
2530
2531         points[5].x = sa->v1->vec.x + width/2 + 2*w;
2532         points[5].y = sa->v1->vec.y + h;
2533
2534         points[6].x = sa->v4->vec.x;
2535         points[6].y = sa->v4->vec.y + h;
2536         
2537         points[7].x = sa->v3->vec.x;
2538         points[7].y = sa->v3->vec.y;
2539
2540         points[8].x = sa->v1->vec.x + width/2 - w;
2541         points[8].y = sa->v1->vec.y;
2542
2543         points[9].x = sa->v1->vec.x + width/2 + w;
2544         points[9].y = sa->v1->vec.y;
2545
2546         if(dir=='u') {
2547                 /* when direction is up, then we flip direction of arrow */
2548                 float cy = sa->v1->vec.y + height;
2549                 for(i=0;i<10;i++) {
2550                         points[i].y -= cy;
2551                         points[i].y = -points[i].y;
2552                         points[i].y += sa->v1->vec.y;
2553                 }
2554         }
2555
2556         glBegin(GL_POLYGON);
2557         for(i=0;i<8;i++)
2558                 glVertex2f(points[i].x, points[i].y);
2559         glEnd();
2560
2561         glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
2562         glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
2563 }
2564
2565 /* draw join shape due to direction of joining */
2566 static void draw_join_shape(ScrArea *sa, char dir)
2567 {
2568         if(dir=='u' || dir=='d')
2569                 draw_vertical_join_shape(sa, dir);
2570         else
2571                 draw_horizontal_join_shape(sa, dir);
2572 }
2573
2574 /* draw screen area darker with arrow (visualisation of future joining) */
2575 static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
2576 {
2577         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2578         glEnable(GL_BLEND);
2579         glColor4ub(0, 0, 0, 105);
2580         draw_join_shape(sa, dir);
2581         glDisable(GL_BLEND);
2582 }
2583
2584 /* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
2585 static void scrarea_draw_shape_light(ScrArea *sa, char dir)
2586 {
2587         glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
2588         glEnable(GL_BLEND);
2589         /* value 181 was hardly computed: 181~105 */
2590         glColor4ub(255, 255, 255, 181);         
2591         draw_join_shape(sa, dir);
2592         glDisable(GL_BLEND);
2593 }
2594
2595 static void joinarea_interactive(ScrArea *area, ScrEdge *onedge)
2596 {
2597         struct ScrArea *sa1 = area, *sa2, *scr;
2598         struct ScrArea *up=0, *down=0, *right=0, *left=0;
2599         struct ScrEdge *se;
2600         unsigned short event;
2601         short ok=0, val=0, mval[2];
2602         char dir;
2603
2604         sa1 = test_edge_area(sa1, onedge);
2605         if(sa1==0) return;
2606
2607         /* find directions with same edge */
2608         sa2= G.curscreen->areabase.first;
2609         while(sa2) {
2610                 if(sa2 != sa1) {
2611                         se= screen_findedge(G.curscreen, sa2->v1, sa2->v2);
2612                         if(onedge==se) right= sa2;
2613                         se= screen_findedge(G.curscreen, sa2->v2, sa2->v3);
2614                         if(onedge==se) down= sa2;
2615                         se= screen_findedge(G.curscreen, sa2->v3, sa2->v4);
2616                         if(onedge==se) left= sa2;
2617                         se= screen_findedge(G.curscreen, sa2->v4, sa2->v1);
2618                         if(onedge==se) up= sa2;
2619                 }
2620                 sa2= sa2->next;
2621         }
2622         
2623         if(left) val++;
2624         if(up) val++;
2625         if(right) val++;
2626         if(down) val++;
2627         
2628         if(val==0) return;
2629         else if(val==1) {
2630                 if(left) {
2631                         right = sa1;
2632                         sa2 = left;
2633                         dir = 'h';
2634                 }
2635                 else if(right) {
2636                         left = sa1;
2637                         sa2 = right;
2638                         dir = 'h';
2639                 }
2640                 else if(up) {
2641                         down = sa1;
2642                         sa2= up;
2643                         dir = 'v';
2644                 }
2645                 else if(down) {
2646                         up = sa1;
2647                         sa2 = down;
2648                         dir = 'v';
2649                 }
2650         }
2651
2652         mywinset(G.curscreen->mainwin);
2653
2654         /* initial set up screen area asigned for destroying */
2655         scr = sa2;
2656
2657         /* set up standard cursor */
2658         set_cursor(CURSOR_STD);
2659
2660         /* should already have a good matrix */
2661         glReadBuffer(GL_FRONT);
2662         glDrawBuffer(GL_FRONT);
2663
2664         /* to prevent flickering after clicking at "Join Areas " */
2665         getmouseco_sc(mval);
2666         if(dir=='h') {
2667                 if(scr==left && mval[0]<=onedge->v1->vec.x) scr = right;
2668                 else if(scr==right && mval[0]>onedge->v1->vec.x) scr = left;
2669         }
2670         else if(dir=='v') {
2671                 if(scr==down && mval[1]<=onedge->v1->vec.y) scr = up;
2672                 else if(scr==up && mval[1]>onedge->v1->vec.y) scr = down;
2673         }
2674
2675         /* draw scr screen area with dark shape */
2676         if(scr==left)
2677                 scrarea_draw_shape_dark(scr,'r');
2678         else if(scr==right)
2679                 scrarea_draw_shape_dark(scr,'l');
2680         else if(scr==up)
2681                 scrarea_draw_shape_dark(scr,'d');
2682         else if(scr==down)
2683                 scrarea_draw_shape_dark(scr,'u');
2684         glFlush();
2685
2686         /* "never ending loop" of interactive selection */
2687         while(!ok) {
2688                 getmouseco_sc(mval);
2689
2690                 /* test if position of mouse is on the "different side" of
2691                  * "joining edge" */
2692                 if(dir=='h') {
2693                         if(scr==left && mval[0]<=onedge->v1->vec.x) {
2694                                 scrarea_draw_shape_light(scr,'r');
2695                                 scr = right;
2696                                 scrarea_draw_shape_dark(scr,'l');
2697                         }
2698                         else if(scr==right && mval[0]>onedge->v1->vec.x) {
2699                                 scrarea_draw_shape_light(scr,'l');
2700                                 scr = left;
2701                                 scrarea_draw_shape_dark(scr,'r');
2702                         }
2703                 }
2704                 else if(dir=='v') {
2705                         if(scr==down && mval[1]<=onedge->v1->vec.y) {
2706                                 scrarea_draw_shape_light(scr,'u');
2707                                 scr = up;
2708                                 scrarea_draw_shape_dark(scr,'d');
2709                         }
2710                         else if(scr==up && mval[1]>onedge->v1->vec.y){
2711                                 scrarea_draw_shape_light(scr,'d');
2712                                 scr = down;
2713                                 scrarea_draw_shape_dark(scr,'u');
2714                         }
2715                 }
2716
2717
2718                 /* get pressed keys and mouse buttons */
2719                 event = extern_qread(&val);
2720
2721                 /* confirm joining of two screen areas */
2722                 if(val && event==LEFTMOUSE) ok= 1;
2723
2724                 /* cancel joining of joining */
2725                 if(val && (event==ESCKEY || event==RIGHTMOUSE)) ok= -1;
2726
2727                 glFlush();
2728         }
2729
2730         glReadBuffer(GL_BACK);
2731         glDrawBuffer(GL_BACK);
2732
2733         /* joining af screen areas was confirmed ... proceed joining */
2734         if(ok==1) {
2735                 if(sa2!=scr) {
2736                         sa1 = sa2;
2737                         sa2 = scr;
2738                 }
2739
2740                 if(sa2==left) {
2741                         sa1->v1= sa2->v1;
2742                         sa1->v2= sa2->v2;
2743                         screen_addedge(G.curscreen, sa1->v2, sa1->v3);
2744                         screen_addedge(G.curscreen, sa1->v1, sa1->v4);
2745                 }
2746                 else if(sa2==up) {
2747                         sa1->v2= sa2->v2;
2748                         sa1->v3= sa2->v3;
2749                         screen_addedge(G.curscreen, sa1->v1, sa1->v2);
2750                         screen_addedge(G.curscreen, sa1->v3, sa1->v4);
2751                 }
2752                 else if(sa2==right) {
2753                         sa1->v3= sa2->v3;
2754                         sa1->v4= sa2->v4;
2755                         screen_addedge(G.curscreen, sa1->v2, sa1->v3);
2756                         screen_addedge(G.curscreen, sa1->v1, sa1->v4);
2757                 }
2758                 else if(sa2==down) {
2759                         sa1->v1= sa2->v1;
2760                         sa1->v4= sa2->v4;
2761                         screen_addedge(G.curscreen, sa1->v1, sa1->v2);
2762                         screen_addedge(G.curscreen, sa1->v3, sa1->v4);
2763                 }
2764         
2765                 del_area(sa2);
2766                 BLI_remlink(&G.curscreen->areabase, sa2);
2767                 MEM_freeN(sa2);
2768                 
2769                 removedouble_scredges();
2770                 removenotused_scredges();
2771                 removenotused_scrverts();
2772                 
2773                 testareas();
2774                 mainqenter(DRAWEDGES, 1);
2775
2776                 /* test cursor en inputwindow */
2777                 mainqenter(MOUSEY, -1);
2778         }
2779 }
2780
2781 static short testsplitpoint(ScrArea *sa, char dir, float fac)
2782 /* return 0: no split possible */
2783 /* else return (integer) screencoordinate split point */
2784 {
2785         short x, y;
2786         
2787         /* area big enough? */
2788         if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
2789         if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
2790
2791         /* to be sure */
2792         if(fac<0.0) fac= 0.0;
2793         if(fac>1.0) fac= 1.0;
2794         
2795         if(dir=='h') {
2796                 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
2797                 
2798                 if(sa->v2->vec.y==G.curscreen->sizey-1 && sa->v2->vec.y- y < HEADERY) 
2799                         y= sa->v2->vec.y- HEADERY;
2800
2801                 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
2802                         y= sa->v1->vec.y+ HEADERY;
2803
2804                 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
2805                 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
2806                 else y-= (y % AREAGRID);
2807
2808                 return y;
2809         }
2810         else {
2811                 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
2812                 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
2813                 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
2814                 else x-= (x % AREAGRID);
2815
2816                 return x;
2817         }
2818 }
2819
2820 static void splitarea(ScrArea *sa, char dir, float fac)
2821 {
2822         bScreen *sc;
2823         ScrArea *newa=NULL;
2824         ScrVert *sv1, *sv2;
2825         short split;
2826         
2827         if(sa==0) return;
2828         
2829         split= testsplitpoint(sa, dir, fac);
2830         if(split==0) return;
2831         
2832         sc= G.curscreen;
2833         
2834         areawinset(sa->win);
2835         
2836         if(dir=='h') {
2837                 /* new vertices */
2838                 sv1= screen_addvert(sc, sa->v1->vec.x, split);
2839                 sv2= screen_addvert(sc, sa->v4->vec.x, split);
2840                 
2841                 /* new edges */
2842                 screen_addedge(sc, sa->v1, sv1);
2843                 screen_addedge(sc, sv1, sa->v2);
2844                 screen_addedge(sc, sa->v3, sv2);
2845                 screen_addedge(sc, sv2, sa->v4);
2846                 screen_addedge(sc, sv1, sv2);
2847                 
2848                 /* new areas: top */
2849                 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
2850                 copy_areadata(newa, sa);
2851
2852                 /* area below */
2853                 sa->v2= sv1;
2854                 sa->v3= sv2;
2855                 
2856         }
2857         else {
2858                 /* new vertices */
2859                 sv1= screen_addvert(sc, split, sa->v1->vec.y);
2860                 sv2= screen_addvert(sc, split, sa->v2->vec.y);
2861                 
2862                 /* new edges */
2863                 screen_addedge(sc, sa->v1, sv1);
2864                 screen_addedge(sc, sv1, sa->v4);
2865                 screen_addedge(sc, sa->v2, sv2);
2866                 screen_addedge(sc, sv2, sa->v3);
2867                 screen_addedge(sc, sv1, sv2);
2868                 
2869                 /* new areas: left */
2870                 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
2871                 copy_areadata(newa, sa);
2872
2873                 /* area right */
2874                 sa->v1= sv1;            
2875                 sa->v2= sv2;
2876         }
2877         
2878         if(sa->spacetype==SPACE_BUTS) {
2879                 addqueue(sa->win, UI_BUT_EVENT, B_BUTSHOME);
2880                 addqueue(newa->win, UI_BUT_EVENT, B_BUTSHOME);
2881         }
2882         
2883         /* remove double vertices en edges */
2884         removedouble_scrverts();
2885         removedouble_scredges();
2886         removenotused_scredges();
2887         
2888         mainqenter(DRAWEDGES, 1);
2889         dodrawscreen= 1;                /* patch! event gets lost,,,? */
2890         testareas();
2891 }
2892
2893 static void scrarea_draw_splitpoint(ScrArea *sa, char dir, float fac)
2894 {
2895         int split= testsplitpoint(sa, dir, fac);
2896
2897         if (split) {
2898                 if(dir=='h') {
2899                         sdrawXORline(sa->totrct.xmin, split, sa->totrct.xmax, split);
2900                         sdrawXORline(sa->totrct.xmin, split-1, sa->totrct.xmax, split-1);
2901                 } else {
2902                         sdrawXORline(split, sa->totrct.ymin, split, sa->totrct.ymax);
2903                         sdrawXORline(split-1, sa->totrct.ymin, split-1, sa->totrct.ymax);
2904                 }
2905         }
2906 }
2907
2908 static void splitarea_interactive(ScrArea *area, ScrEdge *onedge)
2909 {
2910         ScrArea *scr, *sa= area;
2911         float fac= 0.0;
2912         unsigned short event;
2913         short ok= 0, val, split = 0, mval[2], mvalo[2], first= 1;
2914         char dir;
2915         
2916         if(sa->win==0) return;
2917         if(sa->full) return;
2918
2919         dir= scredge_is_horizontal(onedge)?'v':'h';
2920         
2921         mywinset(G.curscreen->mainwin);
2922         /* should already have a good matrix */
2923         glReadBuffer(GL_FRONT);
2924         glDrawBuffer(GL_FRONT);
2925
2926         /* keep track of grid and minsize */
2927         while(ok==0) {
2928                 getmouseco_sc(mval);
2929
2930                 /* this part of code allows to choose, what window will be splited */
2931                 /* cursor is out of the current ScreenArea */
2932                 if((mval[0] < sa->v1->vec.x) || (mval[0] > sa->v3->vec.x) ||
2933                 (mval[1] < sa->v1->vec.y) || (mval[1] > sa->v3->vec.y)){
2934                         scr= (ScrArea*)G.curscreen->areabase.first;
2935                         while(scr){
2936                                 if((mval[0] > scr->v1->vec.x) && (mval[0] < scr->v4->vec.x) &&
2937                                 (mval[1] < scr->v2->vec.y) && (mval[1] > scr->v1->vec.y)){
2938                                         /* test: is ScreenArea enough big for splitting */
2939                                         split= testsplitpoint(scr, dir, fac);
2940                                         if(split){
2941                                                 /* delete old line from previous ScreenArea */
2942                                                 if(!first) scrarea_draw_splitpoint(sa, dir, fac);
2943                                                 sa= scr;
2944                                                 first= 1;
2945                                                 break;
2946                                         }
2947                                 }
2948                                 scr= scr->next;
2949                         }
2950                 }
2951                 
2952                 if (first || mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
2953                         if (!first) {
2954                                 scrarea_draw_splitpoint(sa, dir, fac);
2955                         }
2956
2957                         if(dir=='h') {
2958                                 fac= mval[1]- (sa->v1->vec.y);
2959                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2960                         } else {
2961                                 fac= mval[0]- sa->v1->vec.x;
2962                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
2963                         }
2964
2965                         split= testsplitpoint(sa, dir, fac);
2966                         if (split) {
2967                                 scrarea_draw_splitpoint(sa, dir, fac);
2968                         } else {
2969                                 ok= -1;
2970                         }
2971
2972                         mvalo[0]= mval[0];
2973                         mvalo[1]= mval[1];
2974                         first= 0;                       
2975                 }
2976                 
2977                 event= extern_qread(&val);
2978
2979                 /* change direction of splitting between horizontal and vertical
2980                  * patch was offered by Guillaume */
2981                 if(val && (event==TABKEY || event==MIDDLEMOUSE)) {
2982                         scrarea_draw_splitpoint(sa, dir, fac);
2983                         if(dir=='h') {
2984                                 dir='v';
2985                                 set_cursor(CURSOR_Y_MOVE);
2986                         } else {
2987                                 dir='h';
2988                                 set_cursor(CURSOR_X_MOVE);
2989                         }
2990                         first= 1;
2991                 }
2992
2993                 if(val && event==LEFTMOUSE) {
2994                         if(dir=='h') {
2995                                 fac= split- (sa->v1->vec.y);
2996                                 fac/= sa->v2->vec.y- sa->v1->vec.y;
2997                         }
2998                         else {
2999                                 fac= split- sa->v1->vec.x;
3000                                 fac/= sa->v4->vec.x- sa->v1->vec.x;
3001                         }
3002                         ok= 1;
3003                 }
3004                 if(val && (event==ESCKEY || event==RIGHTMOUSE)) {
3005                         ok= -1;
3006                 }
3007                 glFlush();
3008         }
3009
3010         if (!first) {
3011                 scrarea_draw_splitpoint(sa, dir, fac);
3012                 glFlush();
3013         }
3014         glReadBuffer(GL_BACK);
3015         glDrawBuffer(GL_BACK);
3016
3017         if(ok==1) {
3018                 splitarea(sa, dir, fac);
3019                 mainqenter(DRAWEDGES, 1);
3020                 dodrawscreen= 1;                /* patch! event gets lost,,,? */
3021         }
3022 }
3023
3024 View3D *find_biggest_view3d(void)
3025 {
3026         ScrArea *sa= find_biggest_area_of_type(SPACE_VIEW3D);
3027         
3028         if (sa) {
3029                 return (View3D*) sa->spacedata.first;
3030         } else {
3031                 return NULL;
3032         }
3033 }
3034
3035 ScrArea *find_biggest_area_of_type(int spacecode)
3036 {
3037         ScrArea *sa, *biggest= NULL;
3038         int bigsize= 0;
3039         
3040         for (sa= G.curscreen->areabase.first; sa; sa= sa->next) {
3041                 if (spacecode==0 || sa->spacetype==spacecode) {
3042                         int x= sa->v3->vec.x - sa->v1->vec.x;
3043                         int y= sa->v3->vec.y - sa->v1->vec.y;
3044                         int size= x*x + y*y;
3045                 
3046                         if (!biggest || size>bigsize) {
3047                                 biggest= sa;
3048                                 bigsize= size;
3049                         }
3050                 }
3051         }
3052         
3053         return biggest;
3054 }
3055
3056 ScrArea *find_biggest_area(void)
3057 {
3058         return find_biggest_area_of_type(0);
3059 }
3060
3061 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
3062 {
3063         ScrEdge *se;
3064         ScrVert *sv;
3065         int oneselected;
3066         char dir;
3067         
3068         /* select connected, only in the right direction */
3069         /* 'dir' is the direction of EDGE */
3070
3071         if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
3072         else dir= 'h';
3073
3074         sv= sc->vertbase.first;
3075         while(sv) {
3076                 sv->flag= 0;
3077                 sv= sv->next;
3078         }
3079
3080         edge->v1->flag= 1;
3081         edge->v2->flag= 1;
3082
3083         oneselected= 1;
3084         while(oneselected) {
3085                 se= sc->edgebase.first;
3086                 oneselected= 0;
3087                 while(se) {
3088                         if(se->v1->flag + se->v2->flag==1) {
3089                                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
3090                                         se->v1->flag= se->v2->flag= 1;
3091                                         oneselected= 1;
3092                                 }
3093                                 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
3094                                         se->v1->flag= se->v2->flag= 1;
3095                                         oneselected= 1;
3096                                 }
3097                         }
3098                         se= se->next;
3099                 }
3100         }
3101 }
3102
3103 void test_scale_screen(bScreen *sc)
3104 /* test if screen vertices should be scaled */
3105 /* also check offset */
3106 {
3107         ScrVert *sv=0;
3108         ScrEdge *se;
3109         ScrArea *sa, *san;
3110         int yval;
3111         float facx, facy, tempf, min[2], max[2];
3112
3113         sc->startx= prefstax;
3114         sc->starty= prefstay;
3115         sc->endx= prefstax+prefsizx-1;
3116         sc->endy= prefstay+prefsizy-1;
3117
3118         /* calculate size */
3119         sv= sc->vertbase.first;
3120         min[0]= min[1]= 0.0;
3121         max[0]= sc->sizex;
3122         max[1]= sc->sizey;
3123         while(sv) {
3124                 min[0]= MIN2(min[0], sv->vec.x);
3125                 min[1]= MIN2(min[1], sv->vec.y);
3126                 max[0]= MAX2(max[0], sv->vec.x);
3127                 max[1]= MAX2(max[1], sv->vec.y);
3128                 sv= sv->next;
3129         }
3130
3131         /* always make 0.0 left under */
3132         sv= sc->vertbase.first;
3133         while(sv) {
3134                 sv->vec.x -= min[0];
3135                 sv->vec.y -= min[1];
3136                 sv= sv->next;
3137         }
3138         
3139
3140         sc->sizex= max[0]-min[0];
3141         sc->sizey= max[1]-min[1];
3142
3143         if(sc->sizex!= prefsizx || sc->sizey!= prefsizy) {
3144                 facx= prefsizx;
3145                 facx/= (float)sc->sizex;
3146                 facy= prefsizy;
3147                 facy/= (float)sc->sizey;
3148
3149                 /* make sure it fits! */
3150                 sv= sc->vertbase.first;
3151                 while(sv) {
3152                         tempf= ((float)sv->vec.x)*facx;
3153                         sv->vec.x= (short)(tempf+0.5);
3154                         sv->vec.x+= AREAGRID-1;
3155                         sv->vec.x-=  (sv->vec.x % AREAGRID); 
3156                         
3157                         CLAMP(sv->vec.x, 0, prefsizx);
3158
3159                         tempf= ((float)sv->vec.y )*facy;
3160                         sv->vec.y= (short)(tempf+0.5);
3161                         sv->vec.y+= AREAGRID-1;
3162                         sv->vec.y-=  (sv->vec.y % AREAGRID); 
3163                         
3164                         CLAMP(sv->vec.y, 0, prefsizy);
3165
3166                         sv= sv->next;
3167                 }
3168                 
3169                 sc->sizex= prefsizx;
3170                 sc->sizey= prefsizy;
3171         }
3172
3173         /* test for collapsed areas. This could happen in some blender version... */
3174         sa= sc->areabase.first;
3175         while(sa) {
3176                 san= sa->next;
3177                 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
3178                         del_area(sa);
3179                         BLI_remlink(&sc->areabase, sa);
3180                         MEM_freeN(sa);
3181                 }
3182                 sa= san;
3183         }
3184
3185         /* make each window at least HEADERY high */
3186         sa= sc->areabase.first;
3187         while(sa) {
3188
3189                 if(sa->v1->vec.y+HEADERY > sa->v2->vec.y) {
3190                         /* lower edge */
3191                         se= screen_findedge(sc, sa->v4, sa->v1);
3192                         if(se && sa->v1!=sa->v2 ) {
3193                                 select_connected_scredge(sc, se);
3194                                 
3195                                 /* all selected vertices get the right offset */
3196                                 yval= sa->v2->vec.y-HEADERY;
3197                                 sv= sc->vertbase.first;
3198                                 while(sv) {
3199                                         /* if is a collapsed area */
3200                                         if(sv!=sa->v2 && sv!=sa->v3) {
3201                                                 if(sv->flag) sv->vec.y= yval;
3202                                         }
3203                                         sv= sv->next;
3204                                 }
3205                         }
3206                 }
3207
3208                 sa= sa->next;
3209         }
3210
3211 }
3212
3213 static void draw_front_xor_dirdist_line(char dir, int dist, int start, int end)
3214 {
3215         if (dir=='h') {
3216                 sdrawXORline(start, dist, end, dist);
3217                 sdrawXORline(start, dist+1, end, dist+1);
3218         } else {
3219                 sdrawXORline(dist, start, dist, end);
3220                 sdrawXORline(dist+1, start, dist+1, end);
3221         }
3222 }
3223
3224 static void moveareas(ScrEdge *edge)
3225 {
3226         ScrVert *v1;
3227         ScrArea *sa;
3228         short mvalo[2];
3229         short edge_start, edge_end, edge_position;
3230         short bigger, smaller, headery, areaminy;
3231         int delta, doit;
3232         char dir;
3233         
3234         if(edge->border) return;
3235
3236         dir= scredge_is_horizontal(edge)?'h':'v';
3237         
3238         select_connected_scredge(G.curscreen, edge);
3239
3240         edge_position= (dir=='h')?edge->v1->vec.y:edge->v1->vec.x;
3241         edge_start= 10000;
3242         edge_end= -10000;
3243         for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
3244                 if (v1->flag) {
3245                         if (dir=='h') {
3246                                 edge_start= MIN2(edge_start, v1->vec.x);
3247                                 edge_end= MAX2(edge_end, v1->vec.x);
3248                         } else {
3249                                 edge_start= MIN2(edge_start, v1->vec.y);
3250                                 edge_end= MAX2(edge_end, v1->vec.y);
3251                         }
3252                 }
3253         }
3254
3255         /* now all verices with 'flag==1' are the ones that can be moved. */
3256         /* we check all areas and test for free space with MINSIZE */
3257         bigger= smaller= 10000;
3258         sa= G.curscreen->areabase.first;
3259         while(sa) {
3260                 if(dir=='h') {  /* if top or down edge selected, test height */
3261                         if(sa->headertype) {
3262                                 headery= HEADERY;
3263                                 areaminy= AREAMINY;
3264                         }
3265                         else {
3266                                 headery= 0;
3267                                 areaminy= AREAMINY; /*areaminy= EDGEWIDTH;*/
3268                         }
3269
3270                         if(sa->v1->flag && sa->v4->flag) {
3271                                 int y1;
3272                                 if(sa->v2->vec.y==G.curscreen->sizey-1) /* top edge */
3273                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
3274                                 else 
3275                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
3276                                 bigger= MIN2(bigger, y1);
3277                         }
3278                         else if(sa->v2->flag && sa->v3->flag) {
3279                                 int y1;
3280                                 if(sa->v1->vec.y==0)    /* bottom edge */
3281                                         y1= sa->v2->vec.y - sa->v1->vec.y-headery-EDGEWIDTH;
3282                                 else
3283                                         y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
3284                                 smaller= MIN2(smaller, y1);
3285                         }
3286                 }
3287                 else {  /* if left or right edge selected, test width */
3288                         if(sa->v1->flag && sa->v2->flag) {
3289                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
3290                                 bigger= MIN2(bigger, x1);
3291                         }
3292                         else if(sa->v3->flag && sa->v4->flag) {
3293                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
3294                                 smaller= MIN2(smaller, x1);
3295                         }
3296                 }
3297                 sa= sa->next;
3298         }
3299         
3300         mywinset(G.curscreen->mainwin);
3301
3302         glReadBuffer(GL_FRONT);
3303         glDrawBuffer(GL_FRONT);
3304
3305         doit= delta= 0;
3306         getmouseco_sc(mvalo);
3307         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3308
3309         while (!doit) {
3310                 short val;
3311                 unsigned short event= extern_qread(&val);
3312                 
3313                 if (event==MOUSEY) {
3314                         short mval[2];
3315                         
3316                         getmouseco_sc(mval);
3317                         
3318                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3319
3320                         delta= (dir=='h')?(mval[1]-mvalo[1]):(mval[0]-mvalo[0]);
3321                         delta= CLAMPIS(delta, -smaller, bigger);
3322                         
3323                         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3324                         glFlush();
3325                 } 
3326                 else if (event==LEFTMOUSE) {
3327                         doit= 1;
3328                 } 
3329                 else if (val) {
3330                         if (ELEM(event, ESCKEY, RIGHTMOUSE))
3331                                 doit= -1;
3332                         else if (ELEM(event, SPACEKEY, RETKEY))
3333                                 doit= 1;
3334                 }
3335                 else BIF_wait_for_statechange();
3336                 
3337         }
3338         draw_front_xor_dirdist_line(dir, edge_position+delta, edge_start, edge_end);
3339         glFlush();
3340         glReadBuffer(GL_BACK);
3341         glDrawBuffer(GL_BACK);
3342
3343         if (doit==1) {
3344                 for (v1= G.curscreen->vertbase.first; v1; v1= v1->next) {
3345                         if (v1->flag) {
3346                                         /* that way a nice AREAGRID  */
3347                                 if((dir=='v') && v1->vec.x>0 && v1->vec.x<G.curscreen->sizex-1) {
3348                                   &nb