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