2.5 Branch
[blender.git] / source / blender / editors / screen / screen_edit.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_blenlib.h"
30 #include "BLI_arithb.h"
31
32 #include "BKE_global.h"
33 #include "BKE_library.h"
34 #include "BKE_main.h"
35 #include "BKE_screen.h"
36 #include "BKE_utildefines.h"
37
38 #include "BIF_gl.h"
39 #include "BIF_glutil.h"
40 #include "BIF_resources.h"
41
42 #include "WM_api.h"
43 #include "WM_types.h"
44
45 #include "ED_area.h"
46 #include "ED_screen.h"
47 #include "ED_screen_types.h"
48
49 #include "wm_subwindow.h"
50
51 #include "screen_intern.h"      /* own module include */
52
53 /* ******************* gesture manager ******************* */
54 void ed_gesture_draw_rect(wmWindow *win, wmGesture *gt)
55 {
56         wmGestureRect *rect= (wmGestureRect *)gt;
57         sdrawbox(rect->x1, rect->y1, rect->x2, rect->y2);
58 }
59
60 void ed_gesture_update(wmWindow *win)
61 {
62         wmGesture *gt= (wmGesture *)win->gesture.first;
63
64         while(gt) {
65                 if(gt->type==GESTURE_RECT)
66                         ed_gesture_draw_rect(win, gt);
67                 gt= gt->next;
68         }
69 }
70
71 /* ******************* screen vert, edge, area managing *********************** */
72
73 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
74 {
75         ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
76         sv->vec.x= x;
77         sv->vec.y= y;
78         
79         BLI_addtail(&sc->vertbase, sv);
80         return sv;
81 }
82
83 static void sortscrvert(ScrVert **v1, ScrVert **v2)
84 {
85         ScrVert *tmp;
86         
87         if (*v1 > *v2) {
88                 tmp= *v1;
89                 *v1= *v2;
90                 *v2= tmp;       
91         }
92 }
93
94 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
95 {
96         ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
97         
98         sortscrvert(&v1, &v2);
99         se->v1= v1;
100         se->v2= v2;
101         
102         BLI_addtail(&sc->edgebase, se);
103         return se;
104 }
105
106
107 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
108 {
109         ScrEdge *se;
110         
111         sortscrvert(&v1, &v2);
112         for (se= sc->edgebase.first; se; se= se->next)
113                 if(se->v1==v1 && se->v2==v2)
114                         return se;
115         
116         return NULL;
117 }
118
119 static ScrArea *screen_test_edge_area(bScreen* scr, ScrArea *sa, ScrEdge *se)
120 {
121         /* test if edge is in area, if not, 
122            then find an area that has it */
123   
124         ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
125         
126         if(sa) {
127         se1= screen_findedge(scr, sa->v1, sa->v2);
128                 se2= screen_findedge(scr, sa->v2, sa->v3);
129         se3= screen_findedge(scr, sa->v3, sa->v4);
130                 se4= screen_findedge(scr, sa->v4, sa->v1);
131         }
132         if(se1!=se && se2!=se && se3!=se && se4!=se) {
133                 
134                 sa= scr->areabase.first;
135                 while(sa) {
136                                 /* a bit optimise? */
137                                 if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
138                                 se1= screen_findedge(scr, sa->v1, sa->v2);
139                                         se2= screen_findedge(scr, sa->v2, sa->v3);
140                                         se3= screen_findedge(scr, sa->v3, sa->v4);
141                                         se4= screen_findedge(scr, sa->v4, sa->v1);
142                                         if(se1==se || se2==se || se3==se || se4==se) return sa;
143                                 }
144                                 sa= sa->next;
145                         }
146         }
147
148         return sa;      /* is null when not find */
149 }
150
151 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
152 {
153         ScrArea *sa= NULL;
154         sa= scr->areabase.first;
155         while(sa) {
156                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
157                 sa= sa->next;
158         }
159
160         return sa;
161 }
162
163 static AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
164 {
165         AZone *az= NULL;
166         int i= 0;
167         
168         for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
169                 if(az && az->type == AZONE_TRI) {
170                         if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) break;
171                 }
172                 if(az->type == AZONE_QUAD) {
173                         if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2) break;
174                 }
175         }
176         
177         return az;
178 }
179
180 static void removedouble_scrverts(bScreen *sc)
181 {
182         ScrVert *v1, *verg;
183         ScrEdge *se;
184         ScrArea *sa;
185         
186         verg= sc->vertbase.first;
187         while(verg) {
188                 if(verg->newv==NULL) {  /* !!! */
189                         v1= verg->next;
190                         while(v1) {
191                                 if(v1->newv==NULL) {    /* !?! */
192                                         if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
193                                                 /* printf("doublevert\n"); */
194                                                 v1->newv= verg;
195                                         }
196                                 }
197                                 v1= v1->next;
198                         }
199                 }
200                 verg= verg->next;
201         }
202
203         /* replace pointers in edges and faces */
204         se= sc->edgebase.first;
205         while(se) {
206                 if(se->v1->newv) se->v1= se->v1->newv;
207                 if(se->v2->newv) se->v2= se->v2->newv;
208                 /* edges changed: so.... */
209                 sortscrvert(&(se->v1), &(se->v2));
210                 se= se->next;
211         }
212         sa= sc->areabase.first;
213         while(sa) {
214                 if(sa->v1->newv) sa->v1= sa->v1->newv;
215                 if(sa->v2->newv) sa->v2= sa->v2->newv;
216                 if(sa->v3->newv) sa->v3= sa->v3->newv;
217                 if(sa->v4->newv) sa->v4= sa->v4->newv;
218                 sa= sa->next;
219         }
220
221         /* remove */
222         verg= sc->vertbase.first;
223         while(verg) {
224                 v1= verg->next;
225                 if(verg->newv) {
226                         BLI_remlink(&sc->vertbase, verg);
227                         MEM_freeN(verg);
228                 }
229                 verg= v1;
230         }
231
232 }
233
234 static void removenotused_scrverts(bScreen *sc)
235 {
236         ScrVert *sv, *svn;
237         ScrEdge *se;
238         
239         /* we assume edges are ok */
240         
241         se= sc->edgebase.first;
242         while(se) {
243                 se->v1->flag= 1;
244                 se->v2->flag= 1;
245                 se= se->next;
246         }
247         
248         sv= sc->vertbase.first;
249         while(sv) {
250                 svn= sv->next;
251                 if(sv->flag==0) {
252                         BLI_remlink(&sc->vertbase, sv);
253                         MEM_freeN(sv);
254                 }
255                 else sv->flag= 0;
256                 sv= svn;
257         }
258 }
259
260 static void removedouble_scredges(bScreen *sc)
261 {
262         ScrEdge *verg, *se, *sn;
263         
264         /* compare */
265         verg= sc->edgebase.first;
266         while(verg) {
267                 se= verg->next;
268                 while(se) {
269                         sn= se->next;
270                         if(verg->v1==se->v1 && verg->v2==se->v2) {
271                                 BLI_remlink(&sc->edgebase, se);
272                                 MEM_freeN(se);
273                         }
274                         se= sn;
275                 }
276                 verg= verg->next;
277         }
278 }
279
280 static void removenotused_scredges(bScreen *sc)
281 {
282         ScrEdge *se, *sen;
283         ScrArea *sa;
284         int a=0;
285         
286         /* sets flags when edge is used in area */
287         sa= sc->areabase.first;
288         while(sa) {
289                 se= screen_findedge(sc, sa->v1, sa->v2);
290                 if(se==0) printf("error: area %d edge 1 doesn't exist\n", a);
291                 else se->flag= 1;
292                 se= screen_findedge(sc, sa->v2, sa->v3);
293                 if(se==0) printf("error: area %d edge 2 doesn't exist\n", a);
294                 else se->flag= 1;
295                 se= screen_findedge(sc, sa->v3, sa->v4);
296                 if(se==0) printf("error: area %d edge 3 doesn't exist\n", a);
297                 else se->flag= 1;
298                 se= screen_findedge(sc, sa->v4, sa->v1);
299                 if(se==0) printf("error: area %d edge 4 doesn't exist\n", a);
300                 else se->flag= 1;
301                 sa= sa->next;
302                 a++;
303         }
304         se= sc->edgebase.first;
305         while(se) {
306                 sen= se->next;
307                 if(se->flag==0) {
308                         BLI_remlink(&sc->edgebase, se);
309                         MEM_freeN(se);
310                 }
311                 else se->flag= 0;
312                 se= sen;
313         }
314 }
315
316 static int scredge_is_horizontal(ScrEdge *se)
317 {
318         return (se->v1->vec.y == se->v2->vec.y);
319 }
320
321 static ScrEdge *screen_find_active_scredge(bScreen *sc, int mx, int my)
322 {
323         ScrEdge *se;
324         
325         for (se= sc->edgebase.first; se; se= se->next) {
326                 if (scredge_is_horizontal(se)) {
327                         short min, max;
328                         min= MIN2(se->v1->vec.x, se->v2->vec.x);
329                         max= MAX2(se->v1->vec.x, se->v2->vec.x);
330                         
331                         if (abs(my-se->v1->vec.y)<=2 && mx>=min && mx<=max)
332                                 return se;
333                 } 
334                 else {
335                         short min, max;
336                         min= MIN2(se->v1->vec.y, se->v2->vec.y);
337                         max= MAX2(se->v1->vec.y, se->v2->vec.y);
338                         
339                         if (abs(mx-se->v1->vec.x)<=2 && my>=min && my<=max)
340                                 return se;
341                 }
342         }
343         
344         return NULL;
345 }
346
347 /* danger: is used while areamove! */
348 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
349 {
350         ScrEdge *se;
351         ScrVert *sv;
352         int oneselected;
353         char dir;
354         
355         /* select connected, only in the right direction */
356         /* 'dir' is the direction of EDGE */
357         
358         if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
359         else dir= 'h';
360         
361         sv= sc->vertbase.first;
362         while(sv) {
363                 sv->flag = 0;
364                 sv= sv->next;
365         }
366         
367         edge->v1->flag= 1;
368         edge->v2->flag= 1;
369         
370         oneselected= 1;
371         while(oneselected) {
372                 se= sc->edgebase.first;
373                 oneselected= 0;
374                 while(se) {
375                         if(se->v1->flag + se->v2->flag==1) {
376                                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
377                                         se->v1->flag= se->v2->flag= 1;
378                                         oneselected= 1;
379                                 }
380                                 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
381                                         se->v1->flag= se->v2->flag= 1;
382                                         oneselected= 1;
383                                 }
384                         }
385                         se= se->next;
386                 }
387         }
388 }
389
390 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
391 {
392         AZone *az= NULL;
393         ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
394         sa->v1= v1;
395         sa->v2= v2;
396         sa->v3= v3;
397         sa->v4= v4;
398         sa->headertype= headertype;
399         sa->spacetype= spacetype;
400         
401         BLI_addtail(&sc->areabase, sa);
402         
403         return sa;
404 }
405
406 static void screen_delarea(bScreen *sc, ScrArea *sa)
407 {       
408         BKE_screen_area_free(sa);
409         BLI_remlink(&sc->areabase, sa);
410         MEM_freeN(sa);
411 }
412
413 bScreen *addscreen(wmWindow *win, char *name)
414 {
415         bScreen *sc;
416         ScrVert *sv1, *sv2, *sv3, *sv4;
417         
418         sc= alloc_libblock(&G.main->screen, ID_SCR, name);
419         
420         sc->scene= G.scene;
421         
422         sv1= screen_addvert(sc, 0, 0);
423         sv2= screen_addvert(sc, 0, win->sizey-1);
424         sv3= screen_addvert(sc, win->sizex-1, win->sizey-1);
425         sv4= screen_addvert(sc, win->sizex-1, 0);
426         
427         screen_addedge(sc, sv1, sv2);
428         screen_addedge(sc, sv2, sv3);
429         screen_addedge(sc, sv3, sv4);
430         screen_addedge(sc, sv4, sv1);
431         
432         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
433                 
434         return sc;
435 }
436
437
438 static void screen_copy(bScreen *to, bScreen *from)
439 {
440         ScrVert *s1, *s2;
441         ScrEdge *se;
442         ScrArea *sa, *saf;
443         
444         /* free contents of 'to', is from blenkernel screen.c */
445         free_screen(to);
446         
447         BLI_duplicatelist(&to->vertbase, &from->vertbase);
448         BLI_duplicatelist(&to->edgebase, &from->edgebase);
449         BLI_duplicatelist(&to->areabase, &from->areabase);
450         
451         s2= to->vertbase.first;
452         for(s1= from->vertbase.first; s1; s1= s1->next, s2= s2->next) {
453                 s1->newv= s2;
454         }
455         
456         for(se= to->edgebase.first; se; se= se->next) {
457                 se->v1= se->v1->newv;
458                 se->v2= se->v2->newv;
459                 sortscrvert(&(se->v1), &(se->v2));
460         }
461         
462         saf= from->areabase.first;
463         for(sa= to->areabase.first; sa; sa= sa->next, saf= saf->next) {
464                 sa->v1= sa->v1->newv;
465                 sa->v2= sa->v2->newv;
466                 sa->v3= sa->v3->newv;
467                 sa->v4= sa->v4->newv;
468                 
469                 sa->spacedata.first= sa->spacedata.last= NULL;
470                 sa->uiblocks.first= sa->uiblocks.last= NULL;
471                 sa->panels.first= sa->panels.last= NULL;
472                 sa->regionbase.first= sa->regionbase.last= NULL;
473                 sa->actionzones.first= sa->actionzones.last= NULL;
474                 sa->scriptlink.totscript= 0;
475                 
476                 area_copy_data(sa, saf, 0);
477         }
478         
479         /* put at zero (needed?) */
480         for(s1= from->vertbase.first; s1; s1= s1->next)
481                 s1->newv= NULL;
482
483 }
484
485 bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
486 {
487         bScreen *newsc;
488         
489         if(sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
490         
491         /* make new screen: */
492         newsc= addscreen(win, sc->id.name+2);
493         /* copy all data */
494         screen_copy(newsc, sc);
495         
496         return newsc;
497 }
498
499 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
500 /* used with split operator */
501 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
502 {
503         ScrVert *sav1= sa->v1;
504         ScrVert *sav2= sa->v2;
505         ScrVert *sav3= sa->v3;
506         ScrVert *sav4= sa->v4;
507         ScrVert *sbv1= sb->v1;
508         ScrVert *sbv2= sb->v2;
509         ScrVert *sbv3= sb->v3;
510         ScrVert *sbv4= sb->v4;
511         
512         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
513                 return screen_findedge(screen, sav1, sav2);
514         }
515         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
516                 return screen_findedge(screen, sav2, sav3);
517         }
518         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
519                 return screen_findedge(screen, sav3, sav4);
520         }
521         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
522                 return screen_findedge(screen, sav1, sav4);
523         }
524         
525         return NULL;
526 }
527
528 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
529 /* -1 = not valid check */
530 /* used with split operator */
531 static int area_getorientation(bScreen *screen, ScrArea *sa, ScrArea *sb)
532 {
533         ScrVert *sav1, *sav2, *sav3, *sav4;
534         ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
535
536         if(sa==NULL || sb==NULL) return -1;
537
538         sav1= sa->v1;
539         sav2= sa->v2;
540         sav3= sa->v3;
541         sav4= sa->v4;
542         sbv1= sb->v1;
543         sbv2= sb->v2;
544         sbv3= sb->v3;
545         sbv4= sb->v4;
546         
547         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
548                 return 0;
549         }
550         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
551                 return 1;
552         }
553         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
554                 return 2;
555         }
556         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
557                 return 3;
558         }
559         
560         return -1;
561 }
562
563 /* return 0: no split possible */
564 /* else return (integer) screencoordinate split point */
565 static short testsplitpoint(wmWindow *win, ScrArea *sa, char dir, float fac)
566 {
567         short x, y;
568         
569         // area big enough?
570         if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
571         if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
572
573         // to be sure
574         if(fac<0.0) fac= 0.0;
575         if(fac>1.0) fac= 1.0;
576         
577         if(dir=='h') {
578                 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
579                 
580                 if(sa->v2->vec.y==win->sizey-1 && sa->v2->vec.y- y < HEADERY) 
581                         y= sa->v2->vec.y- HEADERY;
582
583                 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
584                         y= sa->v1->vec.y+ HEADERY;
585
586                 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
587                 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
588                 else y-= (y % AREAGRID);
589
590                 return y;
591         }
592         else {
593                 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
594                 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
595                 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
596                 else x-= (x % AREAGRID);
597
598                 return x;
599         }
600 }
601
602 static ScrArea* splitarea(wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac)
603 {
604         ScrArea *newa=NULL;
605         ScrVert *sv1, *sv2;
606         short split;
607         
608         if(sa==0) return NULL;
609         
610         split= testsplitpoint(win, sa, dir, fac);
611         if(split==0) return NULL;
612         
613         //sc= G.curscreen;
614         
615         //areawinset(sa->win);
616         
617         if(dir=='h') {
618                 /* new vertices */
619                 sv1= screen_addvert(sc, sa->v1->vec.x, split);
620                 sv2= screen_addvert(sc, sa->v4->vec.x, split);
621                 
622                 /* new edges */
623                 screen_addedge(sc, sa->v1, sv1);
624                 screen_addedge(sc, sv1, sa->v2);
625                 screen_addedge(sc, sa->v3, sv2);
626                 screen_addedge(sc, sv2, sa->v4);
627                 screen_addedge(sc, sv1, sv2);
628                 
629                 /* new areas: top */
630                 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
631                 area_copy_data(newa, sa, 0);
632
633                 /* area below */
634                 sa->v2= sv1;
635                 sa->v3= sv2;
636                 
637         }
638         else {
639                 /* new vertices */
640                 sv1= screen_addvert(sc, split, sa->v1->vec.y);
641                 sv2= screen_addvert(sc, split, sa->v2->vec.y);
642                 
643                 /* new edges */
644                 screen_addedge(sc, sa->v1, sv1);
645                 screen_addedge(sc, sv1, sa->v4);
646                 screen_addedge(sc, sa->v2, sv2);
647                 screen_addedge(sc, sv2, sa->v3);
648                 screen_addedge(sc, sv1, sv2);
649                 
650                 /* new areas: left */
651                 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
652                 area_copy_data(newa, sa, 0);
653
654                 /* area right */
655                 sa->v1= sv1;
656                 sa->v2= sv2;
657         }
658         
659         /* remove double vertices en edges */
660         removedouble_scrverts(sc);
661         removedouble_scredges(sc);
662         removenotused_scredges(sc);
663         
664         return newa;
665 }
666
667
668 /* *************************************************************** */
669
670 /* test if screen vertices should be scaled */
671 void screen_test_scale(bScreen *sc, int winsizex, int winsizey)
672 {
673         ScrVert *sv=NULL;
674         ScrArea *sa, *san;
675         int sizex, sizey;
676         float facx, facy, tempf, min[2], max[2];
677         
678         /* calculate size */
679         min[0]= min[1]= 10000.0f;
680         max[0]= max[1]= 0.0f;
681         
682         for(sv= sc->vertbase.first; sv; sv= sv->next) {
683                 min[0]= MIN2(min[0], sv->vec.x);
684                 min[1]= MIN2(min[1], sv->vec.y);
685                 max[0]= MAX2(max[0], sv->vec.x);
686                 max[1]= MAX2(max[1], sv->vec.y);
687         }
688         
689         /* always make 0.0 left under */
690         for(sv= sc->vertbase.first; sv; sv= sv->next) {
691                 sv->vec.x -= min[0];
692                 sv->vec.y -= min[1];
693         }
694         
695         sizex= max[0]-min[0];
696         sizey= max[1]-min[1];
697         
698         if(sizex!= winsizex || sizey!= winsizey) {
699                 facx= winsizex;
700                 facx/= (float)sizex;
701                 facy= winsizey;
702                 facy/= (float)sizey;
703                 
704                 /* make sure it fits! */
705                 for(sv= sc->vertbase.first; sv; sv= sv->next) {
706                         tempf= ((float)sv->vec.x)*facx;
707                         sv->vec.x= (short)(tempf+0.5);
708                         sv->vec.x+= AREAGRID-1;
709                         sv->vec.x-=  (sv->vec.x % AREAGRID); 
710                         
711                         CLAMP(sv->vec.x, 0, winsizex);
712                         
713                         tempf= ((float)sv->vec.y )*facy;
714                         sv->vec.y= (short)(tempf+0.5);
715                         sv->vec.y+= AREAGRID-1;
716                         sv->vec.y-=  (sv->vec.y % AREAGRID); 
717                         
718                         CLAMP(sv->vec.y, 0, winsizey);
719                 }
720         }
721         
722         /* test for collapsed areas. This could happen in some blender version... */
723         for(sa= sc->areabase.first; sa; sa= san) {
724                 san= sa->next;
725                 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
726                         BKE_screen_area_free(sa);
727                         BLI_remlink(&sc->areabase, sa);
728                         MEM_freeN(sa);
729                 }
730         }
731 }
732
733
734
735 #define SCR_BACK 0.55
736 #define SCR_ROUND 12
737
738 /** join areas arrow drawing **/
739 typedef struct point{
740         float x,y;
741 }_point;
742
743 /* draw vertical shape visualising future joining (left as well
744  * right direction of future joining) */
745 static void draw_horizontal_join_shape(ScrArea *sa, char dir)
746 {
747         _point points[10];
748         short i;
749         float w, h;
750         float width = sa->v3->vec.x - sa->v1->vec.x;
751         float height = sa->v3->vec.y - sa->v1->vec.y;
752
753         if(height<width) {
754                 h = height/8;
755                 w = height/4;
756         }
757         else {
758                 h = width/8;
759                 w = width/4;
760         }
761
762         points[0].x = sa->v1->vec.x;
763         points[0].y = sa->v1->vec.y + height/2;
764
765         points[1].x = sa->v1->vec.x;
766         points[1].y = sa->v1->vec.y;
767
768         points[2].x = sa->v4->vec.x - w;
769         points[2].y = sa->v4->vec.y;
770
771         points[3].x = sa->v4->vec.x - w;
772         points[3].y = sa->v4->vec.y + height/2 - 2*h;
773
774         points[4].x = sa->v4->vec.x - 2*w;
775         points[4].y = sa->v4->vec.y + height/2;
776
777         points[5].x = sa->v4->vec.x - w;
778         points[5].y = sa->v4->vec.y + height/2 + 2*h;
779
780         points[6].x = sa->v3->vec.x - w;
781         points[6].y = sa->v3->vec.y;
782
783         points[7].x = sa->v2->vec.x;
784         points[7].y = sa->v2->vec.y;
785
786         points[8].x = sa->v4->vec.x;
787         points[8].y = sa->v4->vec.y + height/2 - h;
788
789         points[9].x = sa->v4->vec.x;
790         points[9].y = sa->v4->vec.y + height/2 + h;
791
792         if(dir=='l') {
793                 /* when direction is left, then we flip direction of arrow */
794                 float cx = sa->v1->vec.x + width;
795                 for(i=0;i<10;i++) {
796                         points[i].x -= cx;
797                         points[i].x = -points[i].x;
798                         points[i].x += sa->v1->vec.x;
799                 }
800         }
801
802         glBegin(GL_POLYGON);
803         for(i=0;i<5;i++)
804                 glVertex2f(points[i].x, points[i].y);
805         glEnd();
806         glBegin(GL_POLYGON);
807         for(i=4;i<8;i++)
808                 glVertex2f(points[i].x, points[i].y);
809         glVertex2f(points[0].x, points[0].y);
810         glEnd();
811
812         glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
813         glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
814 }
815
816 /* draw vertical shape visualising future joining (up/down direction) */
817 static void draw_vertical_join_shape(ScrArea *sa, char dir)
818 {
819         _point points[10];
820         short i;
821         float w, h;
822         float width = sa->v3->vec.x - sa->v1->vec.x;
823         float height = sa->v3->vec.y - sa->v1->vec.y;
824
825         if(height<width) {
826                 h = height/4;
827                 w = height/8;
828         }
829         else {
830                 h = width/4;
831                 w = width/8;
832         }
833
834         points[0].x = sa->v1->vec.x + width/2;
835         points[0].y = sa->v3->vec.y;
836
837         points[1].x = sa->v2->vec.x;
838         points[1].y = sa->v2->vec.y;
839
840         points[2].x = sa->v1->vec.x;
841         points[2].y = sa->v1->vec.y + h;
842
843         points[3].x = sa->v1->vec.x + width/2 - 2*w;
844         points[3].y = sa->v1->vec.y + h;
845
846         points[4].x = sa->v1->vec.x + width/2;
847         points[4].y = sa->v1->vec.y + 2*h;
848
849         points[5].x = sa->v1->vec.x + width/2 + 2*w;
850         points[5].y = sa->v1->vec.y + h;
851
852         points[6].x = sa->v4->vec.x;
853         points[6].y = sa->v4->vec.y + h;
854         
855         points[7].x = sa->v3->vec.x;
856         points[7].y = sa->v3->vec.y;
857
858         points[8].x = sa->v1->vec.x + width/2 - w;
859         points[8].y = sa->v1->vec.y;
860
861         points[9].x = sa->v1->vec.x + width/2 + w;
862         points[9].y = sa->v1->vec.y;
863
864         if(dir=='u') {
865                 /* when direction is up, then we flip direction of arrow */
866                 float cy = sa->v1->vec.y + height;
867                 for(i=0;i<10;i++) {
868                         points[i].y -= cy;
869                         points[i].y = -points[i].y;
870                         points[i].y += sa->v1->vec.y;
871                 }
872         }
873
874         glBegin(GL_POLYGON);
875         for(i=0;i<5;i++)
876                 glVertex2f(points[i].x, points[i].y);
877         glEnd();
878         glBegin(GL_POLYGON);
879         for(i=4;i<8;i++)
880                 glVertex2f(points[i].x, points[i].y);
881         glVertex2f(points[0].x, points[0].y);
882         glEnd();
883
884         glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
885         glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
886 }
887
888 /* draw join shape due to direction of joining */
889 static void draw_join_shape(ScrArea *sa, char dir)
890 {
891         if(dir=='u' || dir=='d')
892                 draw_vertical_join_shape(sa, dir);
893         else
894                 draw_horizontal_join_shape(sa, dir);
895 }
896
897 /* draw screen area darker with arrow (visualisation of future joining) */
898 static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
899 {
900         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
901         glEnable(GL_BLEND);
902         glColor4ub(0, 0, 0, 50);
903         draw_join_shape(sa, dir);
904         glDisable(GL_BLEND);
905 }
906
907 /* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
908 static void scrarea_draw_shape_light(ScrArea *sa, char dir)
909 {
910         glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
911         glEnable(GL_BLEND);
912         /* value 181 was hardly computed: 181~105 */
913         glColor4ub(255, 255, 255, 50);          
914         /* draw_join_shape(sa, dir); */
915         glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
916         glDisable(GL_BLEND);
917 }
918
919 /** screen edges drawing **/
920 static void drawscredge_area(ScrArea *sa)
921 {
922         AZone *az;
923         short x1= sa->v1->vec.x;
924         short xa1= x1+HEADERY;
925         short y1= sa->v1->vec.y;
926         short ya1= y1+HEADERY;
927         short x2= sa->v3->vec.x;
928         short xb2= x2-HEADERY;
929         short y2= sa->v3->vec.y;
930         short yb2= y2-HEADERY;
931         
932         cpack(0x0);
933         
934         /* right border area */
935         sdrawline(x2, y1, x2, y2);
936         
937         /* left border area */
938         if(x1>0) { /* otherwise it draws the emboss of window over */
939                 sdrawline(x1, y1, x1, y2);
940         }
941         
942         /* top border area */
943         sdrawline(x1, y2, x2, y2);
944         
945         /* bottom border area */
946         sdrawline(x1, y1, x2, y1);
947         
948         /* temporary viz for 'action corner' */
949         for(az= sa->actionzones.first; az; az= az->next) {
950                 if(az->type==AZONE_TRI) sdrawtrifill(az->x1, az->y1, az->x2, az->y2, .2, .2, .2);
951                 //if(az->type==AZONE_TRI) sdrawtri(az->x1, az->y1, az->x2, az->y2);
952         }
953 }
954
955 void ED_screen_do_listen(wmWindow *win, wmNotifier *note)
956 {
957         
958         /* generic notes */
959         switch(note->type) {
960                 case WM_NOTE_WINDOW_REDRAW:
961                         win->screen->do_draw= 1;
962                         break;
963                 case WM_NOTE_SCREEN_CHANGED:
964                         win->screen->do_draw= win->screen->do_refresh= 1;
965                         break;
966                 case WM_NOTE_AREA_SPLIT:
967                         printf("WM_NOTE_AREA_SPLIT\n");
968                         break;
969                 case WM_NOTE_AREA_DRAG:
970                         printf("WM_NOTE_AREA_DRAG\n");
971                         break;
972                 case WM_NOTE_GESTURE_CHANGED:
973                         printf("WM_NOTE_GESTURE_CHANGED\n");
974                         win->screen->do_gesture= 1;
975                         break;
976         }
977 }
978
979
980 void ED_screen_draw(wmWindow *win)
981 {
982         ScrArea *sa;
983         ScrArea *sa1=NULL;
984         ScrArea *sa2=NULL;
985         int dir = -1;
986         int dira = -1;
987
988         wm_subwindow_set(win, win->screen->mainwin);
989         
990         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
991                 if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
992                 if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
993                 drawscredge_area(sa);
994         }
995
996         if (sa1 && sa2) {
997                 dir = area_getorientation(win->screen, sa1, sa2);
998                 if (dir >= 0) {
999                         switch(dir) {
1000                                 case 0: /* W */
1001                                         dir = 'r';
1002                                         dira = 'l';
1003                                         break;
1004                                 case 1: /* N */
1005                                         dir = 'd';
1006                                         dira = 'u';
1007                                         break;
1008                                 case 2: /* E */
1009                                         dir = 'l';
1010                                         dira = 'r';
1011                                         break;
1012                                 case 3: /* S */
1013                                         dir = 'u';
1014                                         dira = 'd';
1015                                         break;
1016                         }
1017                 }
1018                 scrarea_draw_shape_dark(sa2, dir);
1019                 scrarea_draw_shape_light(sa1, dira);
1020         }
1021         if(G.f & G_DEBUG) printf("draw screen\n");
1022         win->screen->do_draw= 0;
1023 }
1024
1025 void ED_screen_gesture(wmWindow *win)
1026 {
1027         if(G.f & G_DEBUG) printf("gesture draw screen\n");
1028
1029         if(win->gesture.first) {
1030                 ed_gesture_update(win);
1031         }
1032         win->screen->do_gesture= 0;
1033 }
1034
1035 /* make this screen usable */
1036 /* for file read and first use, for scaling window, area moves */
1037 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
1038 {
1039         ScrArea *sa;
1040         rcti winrct= {0, win->sizex, 0, win->sizey};
1041         
1042         screen_test_scale(win->screen, win->sizex, win->sizey);
1043         
1044         if(win->screen->mainwin==0)
1045                 win->screen->mainwin= wm_subwindow_open(win, &winrct);
1046         else
1047                 wm_subwindow_position(win, win->screen->mainwin, &winrct);
1048         
1049         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1050                 /* set spacetype and region callbacks */
1051                 /* sets subwindow */
1052                 ED_area_initialize(wm, win, sa);
1053         }
1054         
1055         if(G.f & G_DEBUG) printf("set screen\n");
1056         win->screen->do_refresh= 0;
1057
1058 }
1059
1060 /* file read, set all screens, ... */
1061 void ED_screens_initialize(wmWindowManager *wm)
1062 {
1063         wmWindow *win;
1064         
1065         for(win= wm->windows.first; win; win= win->next) {
1066                 
1067                 if(win->screen==NULL)
1068                         win->screen= G.main->screen.first;
1069                 
1070                 ED_screen_refresh(wm, win);
1071         }
1072 }
1073
1074 void placeholder()
1075 {
1076         removenotused_scrverts(NULL);
1077         removenotused_scredges(NULL);
1078 }
1079
1080 /* called in wm_event_system.c. sets state var in screen */
1081 void ED_screen_set_subwinactive(wmWindow *win)
1082 {
1083         if(win->screen) {
1084                 wmEvent *event= win->eventstate;
1085                 ScrArea *sa;
1086                 
1087                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1088                         if(event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
1089                                 if(event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
1090                                         break;
1091                 }
1092                 if(sa) {
1093                         ARegion *ar;
1094                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1095                                 if(BLI_in_rcti(&ar->winrct, event->x, event->y))
1096                                         win->screen->subwinactive= ar->swinid;
1097                         }
1098                 }
1099                 else
1100                         win->screen->subwinactive= win->screen->mainwin;
1101                 
1102         }
1103 }
1104
1105 /* ****************** cursor near edge operator ********************************* */
1106
1107 /* operator cb */
1108 int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event)
1109 {
1110         if (C->screen->subwinactive==C->screen->mainwin) {
1111                 ScrEdge *actedge= screen_find_active_scredge(C->screen, event->x, event->y);
1112                 
1113                 if (actedge && scredge_is_horizontal(actedge)) {
1114                         WM_set_cursor(C, CURSOR_Y_MOVE);
1115                 } else {
1116                         WM_set_cursor(C, CURSOR_X_MOVE);
1117                 }
1118         } else {
1119                 ScrArea *sa= NULL;
1120                 AZone *az= NULL;
1121                 for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1122                         az= is_in_area_actionzone(sa, event->x, event->y);
1123                         if(az!=NULL) break;
1124                 }
1125                 if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT);
1126                 else WM_set_cursor(C, CURSOR_STD);
1127         }
1128         
1129         return OPERATOR_PASS_THROUGH;
1130 }
1131
1132 /* ************** move area edge operator *********************************** */
1133
1134 /* operator state vars used:  
1135            x, y                         mouse coord near edge
1136            delta            movement of edge
1137
1138    internal:
1139
1140    init()   set default property values, find edge based on mouse coords, test
1141             if the edge can be moved, select edges, calculate min and max movement
1142
1143    apply()      apply delta on selection
1144
1145    exit()       cleanup, send notifier
1146
1147    callbacks:
1148
1149    exec()   execute without any user interaction, based on properties
1150             call init(), apply(), exit()
1151
1152    invoke() gets called on mouse click near edge
1153             call init(), add handler
1154
1155    modal()  accept modal events while doing it
1156                         call apply() with delta motion
1157             call exit() and remove handler
1158
1159    cancel() cancel moving
1160
1161 */
1162
1163 typedef struct sAreaMoveData {
1164         int bigger, smaller, origval;
1165         char dir;
1166 } sAreaMoveData;
1167
1168 /* validate selection inside screen, set variables OK */
1169 /* return 0: init failed */
1170 static int move_areas_init (bContext *C, wmOperator *op)
1171 {
1172         ScrEdge *actedge;
1173         ScrArea *sa;
1174         sAreaMoveData *md;
1175         int x, y;
1176
1177         /* required properties */
1178         if(!(OP_get_int(op, "x", &x) && OP_get_int(op, "y", &y)))
1179                 return 0;
1180
1181         /* default properties */
1182         OP_verify_int(op, "delta", 0, NULL);
1183
1184         /* setup */
1185         actedge= screen_find_active_scredge(C->screen, x, y);
1186         if(actedge==NULL) return 0;
1187
1188         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
1189         op->customdata= md;
1190
1191         md->dir= scredge_is_horizontal(actedge)?'h':'v';
1192         if(md->dir=='h') md->origval= actedge->v1->vec.y;
1193         else md->origval= actedge->v1->vec.x;
1194         
1195         select_connected_scredge(C->screen, actedge);
1196
1197         /* now all verices with 'flag==1' are the ones that can be moved. */
1198         /* we check all areas and test for free space with MINSIZE */
1199         md->bigger= md->smaller= 10000;
1200         for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1201                 if(md->dir=='h') {      /* if top or down edge selected, test height */
1202                    
1203                    if(sa->v1->flag && sa->v4->flag) {
1204                            int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
1205                            md->bigger= MIN2(md->bigger, y1);
1206                    }
1207                    else if(sa->v2->flag && sa->v3->flag) {
1208                            int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
1209                            md->smaller= MIN2(md->smaller, y1);
1210                    }
1211                 }
1212                 else {  /* if left or right edge selected, test width */
1213                         if(sa->v1->flag && sa->v2->flag) {
1214                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
1215                                 md->bigger= MIN2(md->bigger, x1);
1216                         }
1217                         else if(sa->v3->flag && sa->v4->flag) {
1218                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
1219                                 md->smaller= MIN2(md->smaller, x1);
1220                         }
1221                 }
1222         }
1223
1224         return 1;
1225 }
1226
1227 /* moves selected screen edge amount of delta */
1228 /* needs init call to work */
1229 static void move_areas_apply(bContext *C, wmOperator *op)
1230 {
1231         ScrVert *v1;
1232         int delta;
1233         sAreaMoveData *md= op->customdata;
1234
1235         OP_get_int(op, "delta", &delta);
1236         
1237         delta= CLAMPIS(delta, -md->smaller, md->bigger);
1238         
1239         for (v1= C->screen->vertbase.first; v1; v1= v1->next) {
1240                 if (v1->flag) {
1241                         /* that way a nice AREAGRID  */
1242                         if((md->dir=='v') && v1->vec.x>0 && v1->vec.x<C->window->sizex-1) {
1243                                 v1->vec.x= md->origval + delta;
1244                                 if(delta != md->bigger && delta != -md->smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
1245                         }
1246                         if((md->dir=='h') && v1->vec.y>0 && v1->vec.y<C->window->sizey-1) {
1247                                 v1->vec.y= md->origval + delta;
1248
1249                                 v1->vec.y+= AREAGRID-1;
1250                                 v1->vec.y-= (v1->vec.y % AREAGRID);
1251                                 
1252                                 /* prevent too small top header */
1253                                 if(v1->vec.y > C->window->sizey-HEADERY)
1254                                         v1->vec.y= C->window->sizey-HEADERY;
1255                         }
1256                 }
1257         }
1258
1259         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1260 }
1261
1262 static void move_areas_exit(bContext *C, wmOperator *op)
1263 {
1264         if(op->customdata)
1265                 MEM_freeN(op->customdata);
1266
1267         /* this makes sure aligned edges will result in aligned grabbing */
1268         removedouble_scrverts(C->screen);
1269         removedouble_scredges(C->screen);
1270 }
1271
1272 static int move_areas_exec(bContext *C, wmOperator *op)
1273 {
1274         if(!move_areas_init(C, op))
1275                 return OPERATOR_CANCELLED;
1276         
1277         move_areas_apply(C, op);
1278         move_areas_exit(C, op);
1279         
1280         return OPERATOR_FINISHED;
1281 }
1282
1283 /* interaction callback */
1284 static int move_areas_invoke(bContext *C, wmOperator *op, wmEvent *event)
1285 {
1286         OP_verify_int(op, "x", event->x, NULL);
1287         OP_verify_int(op, "y", event->y, NULL);
1288
1289         if(!move_areas_init(C, op)) 
1290                 return OPERATOR_PASS_THROUGH;
1291         
1292         /* add temp handler */
1293         WM_event_add_modal_handler(&C->window->handlers, op);
1294         
1295         return OPERATOR_RUNNING_MODAL;
1296 }
1297
1298 static int move_areas_cancel(bContext *C, wmOperator *op)
1299 {
1300         WM_event_remove_modal_handler(&C->window->handlers, op);                                
1301
1302         OP_set_int(op, "delta", 0);
1303         move_areas_apply(C, op);
1304         move_areas_exit(C, op);
1305
1306         return OPERATOR_CANCELLED;
1307 }
1308
1309 /* modal callback for while moving edges */
1310 static int move_areas_modal(bContext *C, wmOperator *op, wmEvent *event)
1311 {
1312         sAreaMoveData *md;
1313         int delta, x, y;
1314
1315         md= op->customdata;
1316
1317         OP_get_int(op, "x", &x);
1318         OP_get_int(op, "y", &y);
1319
1320         /* execute the events */
1321         switch(event->type) {
1322                 case MOUSEMOVE:
1323                         delta= (md->dir == 'v')? event->x - x: event->y - y;
1324                         OP_set_int(op, "delta", delta);
1325
1326                         move_areas_apply(C, op);
1327                         break;
1328                         
1329                 case LEFTMOUSE:
1330                         if(event->val==0) {
1331                                 move_areas_exit(C, op);
1332                                 WM_event_remove_modal_handler(&C->window->handlers, op);                                
1333                                 return OPERATOR_FINISHED;
1334                         }
1335                         break;
1336                         
1337                 case ESCKEY:
1338                         return move_areas_cancel(C, op);
1339         }
1340         
1341         return OPERATOR_RUNNING_MODAL;
1342 }
1343
1344 void ED_SCR_OT_move_areas(wmOperatorType *ot)
1345 {
1346         /* identifiers */
1347         ot->name= "Move area edges";
1348         ot->idname= "ED_SCR_OT_move_areas";
1349
1350         ot->exec= move_areas_exec;
1351         ot->invoke= move_areas_invoke;
1352         ot->cancel= move_areas_cancel;
1353         ot->modal= move_areas_modal;
1354
1355         ot->poll= ED_operator_screen_mainwinactive;
1356 }
1357
1358 /****************** split area ********************/
1359 /* we do split on init, then we work like move_areas
1360         if operation gets cancelled -> join
1361         if operation gets confirmed -> yay
1362 */
1363
1364 #define SPLIT_STARTED   1
1365 #define SPLIT_PROGRESS  2
1366 #define SPLIT_DONE              3
1367
1368 typedef struct sAreaSplitData
1369 {
1370         int state; /* state of operation */
1371         int dir; /* direction of new edge */
1372         int deltax, deltay;
1373         int origval; /* for move areas */
1374         int min,max; /* constraints for moving new edge */
1375         int pos; /* with sa as center, ne is located at: 0=W, 1=N, 2=E, 3=S */
1376         ScrEdge *nedge; /* new edge */
1377         ScrEdge *aedge; /* active edge */
1378         ScrArea *sarea; /* start area */
1379         ScrArea *narea; /* new area */
1380 } sAreaSplitData;
1381
1382 static int split_area_init(bContext *C, wmOperator *op)
1383 {
1384         AZone *az= NULL;
1385         ScrArea *sa= NULL;
1386         sAreaSplitData *sd= NULL;
1387         int x, y;
1388
1389         /* required properties */
1390         if(!(OP_get_int(op, "x", &x) && OP_get_int(op, "y", &y)))
1391                 return 0;
1392         
1393         OP_verify_int(op, "delta", 0, NULL);
1394         OP_verify_int(op, "dir", 0, NULL);
1395         
1396         for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1397                 az= is_in_area_actionzone(sa, x, y);
1398                 if(az!=NULL) break;
1399         }
1400         
1401         if(az==NULL) return 0;
1402         
1403         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_split_area");
1404         op->customdata= sd;
1405         
1406         sd->state= SPLIT_STARTED;
1407         sd->deltax= 0;
1408         sd->deltay= 0;
1409         
1410         return 1;
1411 }
1412
1413 /* the moving of the new egde */
1414 static void split_area_apply(bContext *C, wmOperator *op)
1415 {
1416         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1417         int newval, delta, dir;
1418
1419         OP_get_int(op, "delta", &delta);
1420         OP_get_int(op, "dir", &dir);
1421
1422         newval= sd->origval + delta;
1423         newval= CLAMPIS(newval, -sd->min, sd->max);
1424         
1425         if((dir=='v') && (newval > sd->min && newval < sd->max-1)) {
1426                 sd->nedge->v1->vec.x= newval;
1427                 sd->nedge->v2->vec.x= newval;
1428         }
1429         if((dir=='h') && (newval > sd->min+HEADERY && newval < sd->max-HEADERY)) {
1430                 sd->nedge->v1->vec.y= newval;           
1431                 sd->nedge->v2->vec.y= newval;
1432         }
1433 }
1434
1435 static void split_area_exit(bContext *C, wmOperator *op)
1436 {
1437         if (op->customdata) {
1438                 MEM_freeN(op->customdata);
1439                 op->customdata = NULL;
1440         }
1441         
1442         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1443
1444         /* this makes sure aligned edges will result in aligned grabbing */
1445         removedouble_scrverts(C->screen);
1446         removedouble_scredges(C->screen);
1447 }
1448
1449 static int split_area_init_intern(bContext *C, wmOperator *op, sAreaSplitData *sd)
1450 {
1451         float fac= 0.0;
1452         int dir;
1453
1454         OP_get_int(op, "dir", &dir);
1455
1456         if(dir=='h') {
1457                 OP_get_int(op, "y", &sd->origval);
1458                 fac= 1.0 - ((float)(sd->sarea->v3->vec.y - sd->origval)) / (float)sd->sarea->winy;
1459                 sd->min= sd->aedge->v1->vec.y;
1460                 sd->max= sd->aedge->v2->vec.y;
1461         }
1462         else {
1463                 OP_get_int(op, "x", &sd->origval);
1464                 fac= 1.0 - ((float)(sd->sarea->v4->vec.x - sd->origval)) / (float)sd->sarea->winx;
1465                 sd->min= sd->aedge->v1->vec.x;
1466                 sd->max= sd->aedge->v2->vec.x;
1467         }
1468         
1469         sd->narea= splitarea(C->window, C->screen, sd->sarea, dir, fac);
1470         
1471         if(sd->narea==NULL) return 0;
1472         
1473         sd->nedge= area_findsharededge(C->screen, sd->sarea, sd->narea);
1474         
1475         /* select newly created edge */
1476         select_connected_scredge(C->screen, sd->nedge);
1477         
1478         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1479         
1480         return 1;
1481 }
1482
1483 static int split_area_exec(bContext *C, wmOperator *op)
1484 {
1485         /* XXX: this does nothing, part of the code should be moved
1486          * out of modal() */
1487         
1488         if(!split_area_init(C, op))
1489                 return OPERATOR_CANCELLED;
1490         
1491         split_area_apply(C, op);
1492         split_area_exit(C, op);
1493         
1494         return OPERATOR_FINISHED;
1495 }
1496
1497 static int split_area_invoke(bContext *C, wmOperator *op, wmEvent *event)
1498 {
1499         OP_verify_int(op, "x", event->x, NULL);
1500         OP_verify_int(op, "y", event->y, NULL);
1501
1502         if(!split_area_init(C, op))
1503                 return OPERATOR_PASS_THROUGH;
1504         
1505         /* add temp handler */
1506         WM_event_add_modal_handler(&C->window->handlers, op);
1507         
1508         return OPERATOR_RUNNING_MODAL;
1509 }
1510
1511 /* join areas */
1512 static void split_joincurrent(bContext *C, sAreaSplitData *sd)
1513 {
1514         int orientation= area_getorientation(C->window->screen, sd->sarea, sd->narea);
1515         if(orientation>-1) {
1516                 if(orientation==0) {
1517                         sd->sarea->v1= sd->narea->v1;
1518                         sd->sarea->v2= sd->narea->v2;
1519                         screen_addedge(C->screen, sd->sarea->v2, sd->sarea->v3);
1520                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v4);
1521                 }
1522                 else if(orientation==1) {
1523                         sd->sarea->v2= sd->narea->v2;
1524                         sd->sarea->v3= sd->narea->v3;
1525                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v2);
1526                         screen_addedge(C->screen, sd->sarea->v3, sd->sarea->v4);
1527                 }
1528                 else if(orientation==2) {
1529                         sd->sarea->v3= sd->narea->v3;
1530                         sd->sarea->v4= sd->narea->v4;
1531                         screen_addedge(C->screen, sd->sarea->v2,sd-> sarea->v3);
1532                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v4);
1533                 }
1534                 else if(orientation==3) {
1535                         sd->sarea->v1= sd->narea->v1;
1536                         sd->sarea->v4= sd->narea->v4;
1537                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v2);
1538                         screen_addedge(C->screen, sd->sarea->v3, sd->sarea->v4);
1539                 }
1540
1541                 if (C->area == sd->narea) {
1542                         C->area = NULL;
1543                 }
1544                 screen_delarea(C->screen, sd->narea);
1545                 sd->narea = NULL;
1546                 removedouble_scrverts(C->screen);
1547                 removedouble_scredges(C->screen);
1548         }
1549 }
1550
1551 static int split_area_cancel(bContext *C, wmOperator *op)
1552 {
1553         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1554
1555         WM_event_remove_modal_handler(&C->window->handlers, op);
1556
1557         OP_set_int(op, "delta", 0);
1558         split_joincurrent(C, sd);
1559         split_area_exit(C, op);
1560
1561         return OPERATOR_CANCELLED;
1562 }
1563
1564 static int split_area_modal(bContext *C, wmOperator *op, wmEvent *event)
1565 {
1566         ScrArea *sa= NULL, *sold=NULL;
1567         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1568         int x, y, dir;
1569
1570         OP_get_int(op, "x", &x);
1571         OP_get_int(op, "y", &y);
1572         OP_get_int(op, "dir", &dir);
1573
1574         /* execute the events */
1575         switch(event->type) {
1576                 case MOUSEMOVE:
1577                         if(sd->state==SPLIT_STARTED) {
1578                                 /*
1579                                         We first want to determine direction for split.
1580                                         Get at least one(x or y) delta of minimum 10 pixels.
1581                                         If one dir is delta threshold, and other dir is within "grey area" -> vert/hor split.
1582                                         If we get both over threshold -> subdiv.
1583                                 */
1584                                 sd->deltax= event->x - x;
1585                                 sd->deltay= event->y - y;
1586                                 
1587                                 if(sd->deltax>10 && sd->deltay<4) {
1588                                         printf("split on v\n");
1589                                         sd->state= SPLIT_PROGRESS;
1590                                         OP_set_int(op, "dir", 'v');
1591                                         OP_set_int(op, "delta", sd->deltax);
1592                                 } else if(sd->deltay>10 && sd->deltax<4) {
1593                                         printf("split on h\n");
1594                                         sd->state= SPLIT_PROGRESS;
1595                                         OP_set_int(op, "dir", 'h');
1596                                         OP_set_int(op, "delta", sd->deltay);
1597                                 }
1598                                 
1599                         } else if(sd->state==SPLIT_PROGRESS) {
1600                                 sa= screen_areahascursor(C->screen, event->x, event->y);
1601
1602                                 /* area containing cursor has changed */
1603                                 if(sa && sd->sarea!=sa && sd->narea!=sa) {
1604                                         sold= sd->sarea;
1605                                         split_joincurrent(C, sd);
1606
1607                                         /* now find aedge with same orientation as sd->dir (inverted) */
1608                                         if(dir=='v') {
1609                                                 sd->aedge= screen_findedge(C->screen, sa->v1, sa->v4);
1610                                                 if(sd->aedge==NULL) sd->aedge= screen_findedge(C->screen, sa->v2, sa->v3);
1611                                         }
1612                                         else {
1613                                                 sd->aedge= screen_findedge(C->screen, sa->v1, sa->v2);
1614                                                 if(sd->aedge==NULL) sd->aedge= screen_findedge(C->screen, sa->v3, sa->v4);
1615                                         }
1616
1617                                         /* set sd and op to new init state */
1618                                         sd->sarea= sa;
1619                                         OP_set_int(op, "delta", 0);
1620                                         OP_set_int(op, "x", event->x);
1621                                         OP_set_int(op, "y", event->y);
1622                                         split_area_init_intern(C, op, sd);
1623                                 }
1624                                 else {
1625                                         /* all is cool, update delta according complicated formula */
1626                                         if(dir=='v')
1627                                                 OP_set_int(op, "delta", event->x - y);
1628                                         else
1629                                                 OP_set_int(op, "delta", event->x - y);
1630                                         
1631                                         split_area_apply(C, op);
1632                                 }
1633                         } else if (sd->state==SPLIT_DONE) {
1634                                 /* shouldn't get here anymore */
1635                         }
1636                         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1637                         break;
1638                 case LEFTMOUSE:
1639                         if(event->val==0) { /* mouse up => confirm if not near/on starting edge */
1640                                 split_area_exit(C, op);
1641                                 WM_event_remove_modal_handler(&C->window->handlers, op);
1642                                 return OPERATOR_FINISHED;
1643                         }
1644                         break;
1645                 case RIGHTMOUSE: /* cancel operation */
1646                 case ESCKEY:
1647                         return split_area_cancel(C, op);
1648         }
1649         
1650         return OPERATOR_RUNNING_MODAL;
1651 }
1652
1653 void ED_SCR_OT_split_area(wmOperatorType *ot)
1654 {
1655         ot->name = "Split area";
1656         ot->idname = "ED_SCR_OT_split_area";
1657         
1658         ot->exec= split_area_exec;
1659         ot->invoke= split_area_invoke;
1660         ot->modal= split_area_modal;
1661         
1662         ot->poll= ED_operator_screenactive;
1663 }
1664
1665 /* ************** join area operator ********************************************** */
1666
1667 /* operator state vars used:  
1668            x, y       mouse coord near edge
1669            delta      movement of edge
1670
1671    callbacks:
1672
1673    init()   find edge based on op->veci, 
1674                         test if the edge divides two areas, 
1675                         store active and nonactive area,
1676             
1677    apply()
1678
1679    exit()       cleanup, send notifier
1680
1681    exec()       remove active window, 
1682                         recalc size,
1683                         make nonactive window active, 
1684                         add notifier for redraw.
1685    
1686    invoke() handler gets called on Alt+RMB near edge
1687             call init()
1688             add handler
1689
1690    modal()      accept modal events while doing it
1691                         call apply() with active window and nonactive window
1692             call exit() and remove handler when LMB confirm
1693
1694 */
1695
1696 typedef struct sAreaJoinData
1697 {
1698         int dir;
1699         ScrArea *sa1; /* first area to be considered */
1700         ScrArea *sa2; /* second area to be considered */
1701         ScrArea *scr; /* designed for removal */
1702
1703 } sAreaJoinData;
1704
1705
1706 /* validate selection inside screen, set variables OK */
1707 /* return 0: init failed */
1708 static int join_areas_init(bContext *C, wmOperator *op)
1709 {
1710         ScrArea *actarea = NULL;
1711         sAreaJoinData* jd= NULL;
1712         int x, y;
1713
1714         if(!(OP_get_int(op, "x", &x) && OP_get_int(op, "y", &y)))
1715                 return 0;
1716         
1717         actarea = screen_areahascursor(C->screen, x, y);
1718         if(actarea==NULL)
1719                 return 0;
1720
1721         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_join_areas");
1722                 
1723         jd->sa1 = actarea;
1724         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1725         
1726         op->customdata= jd;
1727         
1728         return 1;
1729 }
1730
1731 /* apply the join of the areas (space types) */
1732 static int join_areas_apply(bContext *C, wmOperator *op)
1733 {
1734         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1735         if (!jd) return 0;
1736
1737         jd->dir = area_getorientation(C->screen, jd->sa1, jd->sa2);
1738         printf("dir is : %i \n", jd->dir);
1739         if (jd->dir < 0)
1740         {
1741                 if (jd->sa1 ) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1742                 if (jd->sa2 ) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1743                 return 0;
1744         }
1745         
1746         if(jd->dir == 0) {
1747                 jd->sa1->v1= jd->sa2->v1;
1748                 jd->sa1->v2= jd->sa2->v2;
1749                 screen_addedge(C->screen, jd->sa1->v2, jd->sa1->v3);
1750                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v4);
1751         }
1752         else if(jd->dir == 1) {
1753                 jd->sa1->v2= jd->sa2->v2;
1754                 jd->sa1->v3= jd->sa2->v3;
1755                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v2);
1756                 screen_addedge(C->screen, jd->sa1->v3, jd->sa1->v4);
1757         }
1758         else if(jd->dir == 2) {
1759                 jd->sa1->v3= jd->sa2->v3;
1760                 jd->sa1->v4= jd->sa2->v4;
1761                 screen_addedge(C->screen, jd->sa1->v2,jd-> sa1->v3);
1762                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v4);
1763         }
1764         else if(jd->dir == 3) {
1765                 jd->sa1->v1= jd->sa2->v1;
1766                 jd->sa1->v4= jd->sa2->v4;
1767                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v2);
1768                 screen_addedge(C->screen, jd->sa1->v3, jd->sa1->v4);
1769         }
1770
1771         if (C->area == jd->sa2) {
1772                 C->area = NULL;
1773         }
1774         screen_delarea(C->screen, jd->sa2);
1775         jd->sa2 = NULL;
1776
1777         jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1778
1779         return 1;
1780 }
1781
1782 static int is_inside_area(ScrArea *ar, short x, short y)
1783 {
1784         int is_inside = 0;
1785         if ( (ar->v1->vec.x < x) && (x < ar->v3->vec.x) ) {
1786                 if ( (y<ar->v3->vec.y) && (ar->v1->vec.y<y) ) {
1787                         is_inside = 1;
1788                 }
1789         }
1790         return is_inside;
1791 }
1792
1793
1794 /* finish operation */
1795 static void join_areas_exit(bContext *C, wmOperator *op)
1796 {
1797         if (op->customdata) {
1798                 MEM_freeN(op->customdata);
1799                 op->customdata = NULL;
1800         }
1801
1802         /* this makes sure aligned edges will result in aligned grabbing */
1803         removedouble_scredges(C->screen);
1804         removenotused_scredges(C->screen);
1805         removenotused_scrverts(C->screen);
1806 }
1807
1808 static int join_areas_exec(bContext *C, wmOperator *op)
1809 {
1810         if(!join_areas_init(C, op)) 
1811                 return OPERATOR_CANCELLED;
1812         
1813         join_areas_apply(C, op);
1814         join_areas_exit(C, op);
1815
1816         return OPERATOR_FINISHED;
1817 }
1818
1819 /* interaction callback */
1820 static int join_areas_invoke(bContext *C, wmOperator *op, wmEvent *event)
1821 {
1822         OP_verify_int(op, "x", event->x, NULL);
1823         OP_verify_int(op, "y", event->y, NULL);
1824
1825         if(!join_areas_init(C, op)) 
1826                 return OPERATOR_PASS_THROUGH;
1827         
1828         /* add temp handler */
1829         WM_event_add_modal_handler(&C->window->handlers, op);
1830         
1831         return OPERATOR_RUNNING_MODAL;
1832 }
1833
1834 static int join_areas_cancel(bContext *C, wmOperator *op)
1835 {
1836         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1837
1838         if (jd->sa1) {
1839                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1840                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1841         }
1842         if (jd->sa2) {
1843                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1844                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1845         }
1846
1847         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1848         WM_event_remove_modal_handler(&C->window->handlers, op);                        
1849         OP_set_int(op, "delta", 0);
1850         join_areas_exit(C, op);
1851
1852         return OPERATOR_CANCELLED;
1853 }
1854
1855 /* modal callback while selecting area (space) that will be removed */
1856 static int join_areas_modal(bContext *C, wmOperator *op, wmEvent *event)
1857 {
1858         /* execute the events */
1859         switch(event->type) {
1860                         
1861                 case MOUSEMOVE:
1862                         {
1863                                 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1864                                 ScrArea *sa = screen_areahascursor(C->screen, event->x, event->y);
1865                                 if (sa) {                                       
1866                                         if (jd->sa1 != sa) {
1867                                                 jd->dir = area_getorientation(C->screen, jd->sa1, sa);
1868                                                 if (jd->dir >= 0)
1869                                                 {
1870                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1871                                                         jd->sa2 = sa;
1872                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1873                                                 } else {
1874                                                         /* we are not bordering on the previously selected area 
1875                                                            we check if area has common border with the one marked for removal
1876                                                            in this case we can swap areas.
1877                                                         */
1878                                                         jd->dir = area_getorientation(C->screen, sa, jd->sa2);
1879                                                         if (jd->dir >= 0) {
1880                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1881                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1882                                                                 jd->sa1 = jd->sa2;
1883                                                                 jd->sa2 = sa;
1884                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1885                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1886                                                         } else {
1887                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1888                                                                 jd->sa2 = NULL;
1889                                                         }
1890                                                 }
1891                                                 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1892                                         } else {
1893                                                 /* we are back in the area previously selected for keeping 
1894                                                  * we swap the areas if possible to allow user to choose */
1895                                                 if (jd->sa2 != NULL) {
1896                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1897                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1898                                                         jd->sa1 = jd->sa2;
1899                                                         jd->sa2 = sa;
1900                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1901                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1902                                                         jd->dir = area_getorientation(C->screen, jd->sa1, jd->sa2);
1903                                                         if (jd->dir < 0)
1904                                                         {
1905                                                                 printf("oops, didn't expect that!\n");
1906                                                         }
1907                                                 } else {
1908                                                         jd->dir = area_getorientation(C->screen, jd->sa1, sa);
1909                                                         if (jd->dir >= 0)
1910                                                         {
1911                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1912                                                                 jd->sa2 = sa;
1913                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1914                                                         }
1915                                                 }
1916                                                 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1917                                         }
1918                                 }
1919                                 
1920                                 break;
1921                         }
1922                 case RIGHTMOUSE:
1923                         if(event->val==0) {
1924                                 join_areas_apply(C, op);
1925                                 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1926                                 join_areas_exit(C, op);
1927                                 WM_event_remove_modal_handler(&C->window->handlers, op);
1928                                 return OPERATOR_FINISHED;
1929                         }
1930                         break;
1931                         
1932                 case ESCKEY:
1933                         return join_areas_cancel(C, op);
1934         }
1935
1936         return OPERATOR_RUNNING_MODAL;
1937 }
1938
1939 /* Operator for joining two areas (space types) */
1940 void ED_SCR_OT_join_areas(wmOperatorType *ot)
1941 {
1942         /* identifiers */
1943         ot->name= "Join area";
1944         ot->idname= "ED_SCR_OT_join_areas";
1945         
1946         /* api callbacks */
1947         ot->exec= join_areas_exec;
1948         ot->invoke= join_areas_invoke;
1949         ot->cancel= join_areas_cancel;
1950         ot->modal= join_areas_modal;
1951
1952         ot->poll= ED_operator_screenactive;
1953 }
1954