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