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