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