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