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