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