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