Changes to the "join area" operator.
[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 static void drawscredge_area(ScrArea *sa)
739 {
740         AZone *az;
741         short x1= sa->v1->vec.x;
742         short xa1= x1+HEADERY;
743         short y1= sa->v1->vec.y;
744         short ya1= y1+HEADERY;
745         short x2= sa->v3->vec.x;
746         short xb2= x2-HEADERY;
747         short y2= sa->v3->vec.y;
748         short yb2= y2-HEADERY;
749         
750         cpack(0x0);
751         
752         /* right border area */
753         sdrawline(x2, y1, x2, y2);
754         
755         /* left border area */
756         if(x1>0) { /* otherwise it draws the emboss of window over */
757                 sdrawline(x1, y1, x1, y2);
758         }
759         
760         /* top border area */
761         sdrawline(x1, y2, x2, y2);
762         
763         /* bottom border area */
764         sdrawline(x1, y1, x2, y1);
765         
766         /* temporary viz for 'action corner' */
767         for(az= sa->actionzones.first; az; az= az->next) {
768                 if(az->type==AZONE_TRI) sdrawtrifill(az->x1, az->y1, az->x2, az->y2, .2, .2, .2);
769                 //if(az->type==AZONE_TRI) sdrawtri(az->x1, az->y1, az->x2, az->y2);
770         }
771 }
772
773 void ED_screen_do_listen(wmWindow *win, wmNotifier *note)
774 {
775         
776         /* generic notes */
777         switch(note->type) {
778                 case WM_NOTE_WINDOW_REDRAW:
779                         win->screen->do_draw= 1;
780                         break;
781                 case WM_NOTE_SCREEN_CHANGED:
782                         win->screen->do_draw= win->screen->do_refresh= 1;
783                         break;
784                 case WM_NOTE_AREA_SPLIT:
785                         printf("WM_NOTE_AREA_SPLIT\n");
786                         break;
787                 case WM_NOTE_AREA_DRAG:
788                         printf("WM_NOTE_AREA_DRAG\n");
789                         break;
790                 case WM_NOTE_GESTURE_CHANGED:
791                         printf("WM_NOTE_GESTURE_CHANGED\n");
792                         win->screen->do_gesture= 1;
793                         break;
794         }
795 }
796
797
798 void ED_screen_draw(wmWindow *win)
799 {
800         ScrArea *sa;
801         
802         wm_subwindow_set(win, win->screen->mainwin);
803         
804         for(sa= win->screen->areabase.first; sa; sa= sa->next)
805                 drawscredge_area(sa);
806
807         printf("draw screen\n");
808         win->screen->do_draw= 0;
809 }
810
811 void ED_screen_gesture(wmWindow *win)
812 {
813         printf("gesture draw screen\n");
814
815         if(win->gesture.first) {
816                 ed_gesture_update(win);
817         }
818         win->screen->do_gesture= 0;
819 }
820
821 /* make this screen usable */
822 /* for file read and first use, for scaling window, area moves */
823 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
824 {
825         ScrArea *sa;
826         rcti winrct= {0, win->sizex, 0, win->sizey};
827         
828         screen_test_scale(win->screen, win->sizex, win->sizey);
829         
830         if(win->screen->mainwin==0)
831                 win->screen->mainwin= wm_subwindow_open(win, &winrct);
832         else
833                 wm_subwindow_position(win, win->screen->mainwin, &winrct);
834         
835         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
836                 /* set spacetype and region callbacks */
837                 /* sets subwindow */
838                 ED_area_initialize(wm, win, sa);
839         }
840         
841         printf("set screen\n");
842         win->screen->do_refresh= 0;
843
844 }
845
846 /* file read, set all screens, ... */
847 void ED_screens_initialize(wmWindowManager *wm)
848 {
849         wmWindow *win;
850         
851         for(win= wm->windows.first; win; win= win->next) {
852                 
853                 if(win->screen==NULL)
854                         win->screen= G.main->screen.first;
855                 
856                 ED_screen_refresh(wm, win);
857         }
858 }
859
860 void placeholder()
861 {
862         removenotused_scrverts(NULL);
863         removenotused_scredges(NULL);
864 }
865
866 /* called in wm_event_system.c. sets state var in screen */
867 void ED_screen_set_subwinactive(wmWindow *win)
868 {
869         if(win->screen) {
870                 wmEvent *event= win->eventstate;
871                 ScrArea *sa;
872                 
873                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
874                         if(event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
875                                 if(event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
876                                         break;
877                 }
878                 if(sa) {
879                         ARegion *ar;
880                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
881                                 if(BLI_in_rcti(&ar->winrct, event->x, event->y))
882                                         win->screen->subwinactive= ar->swinid;
883                         }
884                 }
885                 else
886                         win->screen->subwinactive= win->screen->mainwin;
887                 
888         }
889 }
890
891 /* ****************** cursor near edge operator ********************************* */
892
893 /* operator cb */
894 int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event)
895 {
896         if (C->screen->subwinactive==C->screen->mainwin) {
897                 ScrEdge *actedge= screen_find_active_scredge(C->screen, event->x, event->y);
898                 
899                 if (actedge && scredge_is_horizontal(actedge)) {
900                         WM_set_cursor(C, CURSOR_Y_MOVE);
901                 } else {
902                         WM_set_cursor(C, CURSOR_X_MOVE);
903                 }
904         } else {
905                 ScrArea *sa= NULL;
906                 AZone *az= NULL;
907                 for(sa= C->screen->areabase.first; sa; sa= sa->next) {
908                         az= is_in_area_actionzone(sa, event->x, event->y);
909                         if(az!=NULL) break;
910                 }
911                 if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT);
912                 else WM_set_cursor(C, CURSOR_STD);
913         }
914         
915         return 1;
916 }
917
918 /* ************** move area edge operator ********************************************** */
919
920 /* operator state vars used:  
921            op->veci   mouse coord near edge
922            op->delta  movement of edge
923
924    callbacks:
925
926    init()   find edge based on op->veci, test if the edge can be moved, select edges,
927             clear delta, calculate min and max movement
928
929    exec()       apply op->delta on selection
930    
931    invoke() handler gets called on a mouse click near edge
932             call init()
933             add handler
934
935    modal()      accept modal events while doing it
936                         call exec() with delta motion
937             call exit() and remove handler
938
939    exit()       cleanup, send notifier
940
941 */
942
943 /* validate selection inside screen, set variables OK */
944 /* return 0: init failed */
945 static int move_areas_init (bContext *C, wmOperator *op)
946 {
947         ScrEdge *actedge= screen_find_active_scredge(C->screen, op->veci.x, op->veci.y);
948         ScrArea *sa;
949         int bigger, smaller, dir, origval;
950         
951         if(actedge==NULL) return 0;
952         
953         dir= scredge_is_horizontal(actedge)?'h':'v';
954         if(dir=='h') origval= actedge->v1->vec.y;
955         else origval= actedge->v1->vec.x;
956         
957         select_connected_scredge(C->screen, actedge);
958
959         /* now all verices with 'flag==1' are the ones that can be moved. */
960         /* we check all areas and test for free space with MINSIZE */
961         bigger= smaller= 10000;
962         for(sa= C->screen->areabase.first; sa; sa= sa->next) {
963                 if(dir=='h') {  /* if top or down edge selected, test height */
964                    
965                    if(sa->v1->flag && sa->v4->flag) {
966                            int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
967                            bigger= MIN2(bigger, y1);
968                    }
969                    else if(sa->v2->flag && sa->v3->flag) {
970                            int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
971                            smaller= MIN2(smaller, y1);
972                    }
973                 }
974                 else {  /* if left or right edge selected, test width */
975                         if(sa->v1->flag && sa->v2->flag) {
976                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
977                                 bigger= MIN2(bigger, x1);
978                         }
979                         else if(sa->v3->flag && sa->v4->flag) {
980                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
981                                 smaller= MIN2(smaller, x1);
982                         }
983                 }
984         }
985
986         OP_set_int(op, "bigger", bigger);
987         OP_set_int(op, "smaller", smaller);
988         OP_set_int(op, "dir", dir);
989         OP_set_int(op, "origval", origval);
990
991         return 1;
992 }
993
994 /* moves selected screen edge amount of delta */
995 /* needs init call to work */
996 static int move_areas_exec(bContext *C, wmOperator *op)
997 {
998         ScrVert *v1;
999         int bigger, smaller, dir, origval;
1000
1001         OP_get_int(op, "bigger", &bigger);
1002         OP_get_int(op, "smaller", &smaller);
1003         OP_get_int(op, "dir", &dir);
1004         OP_get_int(op, "origval", &origval);
1005         
1006         op->delta= CLAMPIS(op->delta, -smaller, bigger);
1007         
1008         for (v1= C->screen->vertbase.first; v1; v1= v1->next) {
1009                 if (v1->flag) {
1010                         /* that way a nice AREAGRID  */
1011                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<C->window->sizex-1) {
1012                                 v1->vec.x= origval + op->delta;
1013                                 if(op->delta != bigger && op->delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
1014                         }
1015                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<C->window->sizey-1) {
1016                                 v1->vec.y= origval + op->delta;
1017
1018                                 v1->vec.y+= AREAGRID-1;
1019                                 v1->vec.y-= (v1->vec.y % AREAGRID);
1020                                 
1021                                 /* prevent too small top header */
1022                                 if(v1->vec.y > C->window->sizey-HEADERY)
1023                                         v1->vec.y= C->window->sizey-HEADERY;
1024                         }
1025                 }
1026         }
1027         return 1;
1028 }
1029
1030 static int move_areas_exit(bContext *C, wmOperator *op)
1031 {
1032         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1033
1034         /* this makes sure aligned edges will result in aligned grabbing */
1035         removedouble_scrverts(C->screen);
1036         removedouble_scredges(C->screen);
1037
1038         OP_free_property(op);   
1039         return 1;
1040 }
1041
1042 /* interaction callback */
1043 /* return 0 = stop evaluating for next handlers */
1044 static int move_areas_invoke (bContext *C, wmOperator *op, wmEvent *event)
1045 {
1046         
1047         /* operator arguments and storage */
1048         op->properties = NULL;
1049         op->delta= 0;
1050         op->veci.x= event->x;
1051         op->veci.y= event->y;
1052         
1053         if(0==move_areas_init(C, op)) 
1054                 return 1;
1055         
1056         /* add temp handler */
1057         WM_event_add_modal_handler(&C->window->handlers, op);
1058         
1059         return 0;
1060 }
1061
1062 /* modal callback for while moving edges */
1063 /* return 0 = stop evaluating for next handlers */
1064 static int move_areas_modal (bContext *C, wmOperator *op, wmEvent *event)
1065 {
1066         int dir;
1067
1068         OP_get_int(op, "dir", &dir);
1069
1070         /* execute the events */
1071         switch(event->type) {
1072                 case MOUSEMOVE:
1073                         
1074                         if(dir=='v')
1075                                 op->delta= event->x - op->veci.x;
1076                         else
1077                                 op->delta= event->y - op->veci.y;
1078                         
1079                         move_areas_exec(C, op);
1080                         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1081                         break;
1082                         
1083                 case LEFTMOUSE:
1084                         if(event->val==0) {
1085                                 move_areas_exit(C, op);
1086                                 WM_event_remove_modal_handler(&C->window->handlers, op);                                
1087                         }
1088                         break;
1089                         
1090                 case ESCKEY:
1091                         op->delta= 0;
1092                         move_areas_exec(C, op);
1093                         
1094                         WM_event_remove_modal_handler(&C->window->handlers, op);
1095                         move_areas_exit(C, op);
1096                         break;
1097         }
1098         
1099         return 1;
1100 }
1101
1102 void ED_SCR_OT_move_areas(wmOperatorType *ot)
1103 {
1104         
1105         /* identifiers */
1106         ot->name= "Move area edges";
1107         ot->idname= "ED_SCR_OT_move_areas";
1108
1109         ot->init= move_areas_init;
1110         ot->invoke= move_areas_invoke;
1111         ot->modal= move_areas_modal;
1112         ot->exec= move_areas_exec;
1113         ot->exit= move_areas_exit;
1114
1115         ot->poll= ED_operator_screen_mainwinactive;
1116 }
1117
1118 /****************** split area ********************/
1119 /* we do split on init, then we work like move_areas
1120         if operation gets cancelled -> join
1121         if operation gets confirmed -> yay
1122 */
1123
1124 #define SPLIT_STARTED   1
1125 #define SPLIT_PROGRESS  2
1126 #define SPLIT_DONE              3
1127
1128 typedef struct sAreaSplitData
1129 {
1130         int state; /* state of operation */
1131         int dir; /* direction of new edge */
1132         int deltax, deltay;
1133         int origval; /* for move areas */
1134         int min,max; /* constraints for moving new edge */
1135         int pos; /* with sa as center, ne is located at: 0=W, 1=N, 2=E, 3=S */
1136         ScrEdge *nedge; /* new edge */
1137         ScrEdge *aedge; /* active edge */
1138         ScrArea *sarea; /* start area */
1139         ScrArea *narea; /* new area */
1140 } sAreaSplitData;
1141
1142 /* the moving of the new egde */
1143 static int split_area_exec(bContext *C, wmOperator *op)
1144 {
1145         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1146         int newval= sd->origval + op->delta;
1147         
1148         newval= CLAMPIS(newval, -sd->min, sd->max);
1149         
1150         if((sd->dir=='v') && (newval > sd->min && newval < sd->max-1)) {
1151                 sd->nedge->v1->vec.x= newval;
1152                 sd->nedge->v2->vec.x= newval;
1153         }
1154         if((sd->dir=='h') && (newval > sd->min+HEADERY && newval < sd->max-HEADERY)) {
1155                 sd->nedge->v1->vec.y= newval;           
1156                 sd->nedge->v2->vec.y= newval;
1157         }
1158         return 1;
1159 }
1160
1161 static int split_area_exit(bContext *C, wmOperator *op)
1162 {
1163         if (op->customdata) {
1164                 MEM_freeN(op->customdata);
1165                 op->customdata = NULL;
1166         }
1167         
1168         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1169
1170         /* this makes sure aligned edges will result in aligned grabbing */
1171         removedouble_scrverts(C->screen);
1172         removedouble_scredges(C->screen);
1173         
1174         return 1;
1175 }
1176
1177 static int split_initintern(bContext *C, wmOperator *op, sAreaSplitData *sd)
1178 {
1179         float fac= 0.0;
1180         if(sd->dir=='h') {
1181                 sd->origval= op->veci.y;
1182                 fac= 1.0 - ((float)(sd->sarea->v3->vec.y - op->veci.y)) / (float)sd->sarea->winy;
1183                 sd->min= sd->aedge->v1->vec.y;
1184                 sd->max= sd->aedge->v2->vec.y;
1185         }
1186         else {
1187                 sd->origval= op->veci.x;
1188                 fac= 1.0 - ((float)(sd->sarea->v4->vec.x - op->veci.x)) / (float)sd->sarea->winx;
1189                 sd->min= sd->aedge->v1->vec.x;
1190                 sd->max= sd->aedge->v2->vec.x;
1191         }
1192         
1193         sd->narea= splitarea(C->window, C->screen, sd->sarea, sd->dir, fac);
1194         
1195         if(sd->narea==NULL) return 0;
1196         
1197         sd->nedge= area_findsharededge(C->screen, sd->sarea, sd->narea);
1198         
1199         /* select newly created edge */
1200         select_connected_scredge(C->screen, sd->nedge);
1201         
1202         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1203         
1204         return 1;
1205 }
1206
1207 static int split_area_init (bContext *C, wmOperator *op)
1208 {
1209         AZone *az= NULL;
1210         ScrArea *sa= NULL;
1211         sAreaSplitData *sd= NULL;
1212         
1213         for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1214                 az= is_in_area_actionzone(sa, op->veci.x, op->veci.y);
1215                 if(az!=NULL) break;
1216         }
1217         
1218         if(az==NULL) return 0;
1219         
1220         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_split_area");
1221         op->customdata= sd;
1222         
1223         sd->state= SPLIT_STARTED;
1224         sd->deltax= 0;
1225         sd->deltay= 0;
1226         
1227         return 1;
1228 }
1229
1230 static int split_area_invoke(bContext *C, wmOperator *op, wmEvent *event)
1231 {
1232         /* operator arguments and storage */
1233         op->customdata= NULL;
1234         op->delta= 0;
1235         op->veci.x= event->x;
1236         op->veci.y= event->y;
1237
1238         op->customdata= NULL;
1239         
1240         if(0==split_area_init(C, op)) 
1241                 return 1;
1242         
1243         /* add temp handler */
1244         WM_event_add_modal_handler(&C->window->handlers, op);
1245         
1246         return 0;
1247 }
1248
1249 /* join areas */
1250 static void split_joincurrent(bContext *C, sAreaSplitData *sd)
1251 {
1252         int orientation= area_getorientation(C->window->screen, sd->sarea, sd->narea);
1253         if(orientation>-1) {
1254                 if(orientation==0) {
1255                         sd->sarea->v1= sd->narea->v1;
1256                         sd->sarea->v2= sd->narea->v2;
1257                         screen_addedge(C->screen, sd->sarea->v2, sd->sarea->v3);
1258                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v4);
1259                 }
1260                 else if(orientation==1) {
1261                         sd->sarea->v2= sd->narea->v2;
1262                         sd->sarea->v3= sd->narea->v3;
1263                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v2);
1264                         screen_addedge(C->screen, sd->sarea->v3, sd->sarea->v4);
1265                 }
1266                 else if(orientation==2) {
1267                         sd->sarea->v3= sd->narea->v3;
1268                         sd->sarea->v4= sd->narea->v4;
1269                         screen_addedge(C->screen, sd->sarea->v2,sd-> sarea->v3);
1270                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v4);
1271                 }
1272                 else if(orientation==3) {
1273                         sd->sarea->v1= sd->narea->v1;
1274                         sd->sarea->v4= sd->narea->v4;
1275                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v2);
1276                         screen_addedge(C->screen, sd->sarea->v3, sd->sarea->v4);
1277                 }
1278
1279                 if (C->curarea == sd->narea) {
1280                         C->curarea = NULL;
1281                 }
1282                 screen_delarea(C->screen, sd->narea);
1283                 sd->narea = NULL;
1284                 removedouble_scrverts(C->screen);
1285                 removedouble_scredges(C->screen);
1286         }
1287 }
1288
1289 static int split_area_modal(bContext *C, wmOperator *op, wmEvent *event)
1290 {
1291         ScrArea *sa= NULL, *sold=NULL;
1292         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1293
1294         /* execute the events */
1295         switch(event->type) {
1296                 case MOUSEMOVE:
1297                         if(sd->state==SPLIT_STARTED) {
1298                                 /*
1299                                         We first want to determine direction for split.
1300                                         Get at least one(x or y) delta of minimum 10 pixels.
1301                                         If one dir is delta threshold, and other dir is within "grey area" -> vert/hor split.
1302                                         If we get both over threshold -> subdiv.
1303                                 */
1304                                 sd->deltax= event->x - op->veci.x;
1305                                 sd->deltay= event->y - op->veci.y;
1306                                 
1307                                 if(sd->deltax>10 && sd->deltay<4) {
1308                                         printf("split on v\n");
1309                                         sd->dir='v';
1310                                         sd->state= SPLIT_PROGRESS;
1311                                         op->delta= sd->deltax;
1312                                 } else if(sd->deltay>10 && sd->deltax<4) {
1313                                         printf("split on h\n");
1314                                         sd->dir='h';
1315                                         sd->state= SPLIT_PROGRESS;
1316                                         op->delta= sd->deltay;
1317                                 }
1318                                 
1319                         } else if(sd->state==SPLIT_PROGRESS) {
1320                                 sa= screen_areahascursor(C->screen, event->x, event->y);
1321
1322                                 /* area containing cursor has changed */
1323                                 if(sa && sd->sarea!=sa && sd->narea!=sa) {
1324                                         sold= sd->sarea;
1325                                         split_joincurrent(C, sd);
1326
1327                                         /* now find aedge with same orientation as sd->dir (inverted) */
1328                                         if(sd->dir=='v') {
1329                                                 sd->aedge= screen_findedge(C->screen, sa->v1, sa->v4);
1330                                                 if(sd->aedge==NULL) sd->aedge= screen_findedge(C->screen, sa->v2, sa->v3);
1331                                         }
1332                                         else {
1333                                                 sd->aedge= screen_findedge(C->screen, sa->v1, sa->v2);
1334                                                 if(sd->aedge==NULL) sd->aedge= screen_findedge(C->screen, sa->v3, sa->v4);
1335                                         }
1336
1337                                         /* set sd and op to new init state */
1338                                         sd->sarea= sa;
1339                                         op->delta= 0;
1340                                         op->veci.x= event->x;
1341                                         op->veci.y= event->y;
1342                                         split_initintern(C, op, sd);
1343                                 }
1344                                 else {
1345                                         /* all is cool, update delta according complicated formula */
1346                                         if(sd->dir=='v')
1347                                                 op->delta= event->x - op->veci.x;
1348                                         else
1349                                                 op->delta= event->y - op->veci.y;
1350                                         
1351                                         split_area_exec(C, op);
1352                                 }
1353                         } else if (sd->state==SPLIT_DONE) {
1354                                 /* shouldn't get here anymore */
1355                         }
1356                         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1357                         break;
1358                 case LEFTMOUSE:
1359                         if(event->val==0) { /* mouse up => confirm if not near/on starting edge */
1360                                 split_area_exit(C, op);
1361                                 WM_event_remove_modal_handler(&C->window->handlers, op);
1362                         }
1363                         break;
1364                 case RIGHTMOUSE: /* cancel operation */
1365                 case ESCKEY:
1366                         op->delta= 0;
1367                         split_joincurrent(C, sd);
1368                         WM_event_remove_modal_handler(&C->window->handlers, op);
1369                         split_area_exit(C, op);
1370                         break;
1371         }
1372         
1373         return 1;
1374 }
1375
1376 void ED_SCR_OT_split_area(wmOperatorType *ot)
1377 {
1378         ot->name = "Split area";
1379         ot->idname = "ED_SCR_OT_split_area";
1380         
1381         ot->init= split_area_init;
1382         ot->invoke= split_area_invoke;
1383         ot->modal= split_area_modal;
1384         ot->exec= split_area_exec;
1385         ot->exit= split_area_exit;
1386         
1387         ot->poll= ED_operator_screenactive;
1388 }
1389
1390 /* ************** join area operator ********************************************** */
1391
1392 /* operator state vars used:  
1393            op->veci   mouse coord near edge
1394            op->delta  movement of edge
1395
1396    callbacks:
1397
1398    init()   find edge based on op->veci, 
1399                         test if the edge divides two areas, 
1400                         store active and nonactive area,
1401             
1402
1403    exec()       remove active window, 
1404                         recalc size,
1405                         make nonactive window active, 
1406                         add notifier for redraw.
1407    
1408    invoke() handler gets called on Alt+RMB near edge
1409             call init()
1410             add handler
1411
1412    modal()      accept modal events while doing it
1413                         call exec() with active window and nonactive window
1414             call exit() and remove handler when LMB confirm
1415
1416    exit()       cleanup, send notifier
1417
1418 */
1419
1420 typedef struct sAreaJoinData
1421 {
1422         int dir;
1423         ScrArea *sa1; /* first area to be considered */
1424         ScrArea *sa2; /* second area to be considered */
1425         ScrArea *scr; /* designed for removal */
1426
1427 } sAreaJoinData;
1428
1429
1430 /* validate selection inside screen, set variables OK */
1431 /* return 0: init failed */
1432 static int join_areas_init (bContext *C, wmOperator *op)
1433 {
1434         ScrArea *actarea = C->curarea;
1435         sAreaJoinData* jd= NULL;
1436         
1437         if (actarea==NULL)
1438         {
1439                 return 0;
1440         }
1441         
1442         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_join_areas");
1443                 
1444         jd->sa1 = actarea;
1445         /* initial set up screen area asigned for destroying */
1446         jd->scr = jd->sa2;      
1447         op->customdata= jd;
1448         
1449         return 1;
1450 }
1451
1452 /* apply the join of the areas (space types) */
1453 static int join_areas_exec(bContext *C, wmOperator *op)
1454 {
1455         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1456         if (!jd) return 0;
1457         
1458         jd->dir = area_getorientation(C->screen, jd->sa1, jd->sa2);
1459         
1460         printf("dir is : %i \n", jd->dir);
1461         if (jd->dir < 0)
1462         {
1463                 return 0;
1464         }
1465         
1466         if(jd->dir == 0) {
1467                 jd->sa1->v1= jd->sa2->v1;
1468                 jd->sa1->v2= jd->sa2->v2;
1469                 screen_addedge(C->screen, jd->sa1->v2, jd->sa1->v3);
1470                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v4);
1471         }
1472         else if(jd->dir == 1) {
1473                 jd->sa1->v2= jd->sa2->v2;
1474                 jd->sa1->v3= jd->sa2->v3;
1475                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v2);
1476                 screen_addedge(C->screen, jd->sa1->v3, jd->sa1->v4);
1477         }
1478         else if(jd->dir == 2) {
1479                 jd->sa1->v3= jd->sa2->v3;
1480                 jd->sa1->v4= jd->sa2->v4;
1481                 screen_addedge(C->screen, jd->sa1->v2,jd-> sa1->v3);
1482                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v4);
1483         }
1484         else if(jd->dir == 3) {
1485                 jd->sa1->v1= jd->sa2->v1;
1486                 jd->sa1->v4= jd->sa2->v4;
1487                 screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v2);
1488                 screen_addedge(C->screen, jd->sa1->v3, jd->sa1->v4);
1489         }
1490
1491         if (C->curarea == jd->sa2) {
1492                 C->curarea = NULL;
1493         }
1494         screen_delarea(C->screen, jd->sa2);
1495         jd->sa2 = NULL;
1496         return 1;
1497 }
1498 /* interaction callback */
1499 /* return 0 = stop evaluating for next handlers */
1500 static int join_areas_invoke (bContext *C, wmOperator *op, wmEvent *event)
1501 {
1502         /* operator arguments and storage */
1503         op->delta= 0;
1504         op->veci.x= event->x;
1505         op->veci.y= event->y;
1506         op->customdata = NULL;
1507         printf("invoke \n");
1508         if(0==join_areas_init(C, op)) 
1509                 return 1;
1510         
1511         /* add temp handler */
1512         WM_event_add_modal_handler(&C->window->handlers, op);
1513         
1514         return 0;
1515 }
1516
1517 static int is_inside_area(ScrArea *ar, short x, short y)
1518 {
1519         int is_inside = 0;
1520         if ( (ar->v1->vec.x < x) && (x < ar->v3->vec.x) ) {
1521                 if ( (y<ar->v3->vec.y) && (ar->v1->vec.y<y) ) {
1522                         is_inside = 1;
1523                 }
1524         }
1525         return is_inside;
1526 }
1527
1528
1529 /* finish operation */
1530 static int join_areas_exit(bContext *C, wmOperator *op)
1531 {
1532         if (op->customdata) {
1533                 MEM_freeN(op->customdata);
1534                 op->customdata = NULL;
1535         }
1536
1537         /* this makes sure aligned edges will result in aligned grabbing */
1538         removedouble_scredges(C->screen);
1539         removenotused_scredges(C->screen);
1540         removenotused_scrverts(C->screen);
1541         printf("exit \n");
1542         return 1;
1543 }
1544
1545 /* modal callback while selecting area (space) that will be removed */
1546 /* return 0 = stop evaluating for next handlers */
1547 static int join_areas_modal (bContext *C, wmOperator *op, wmEvent *event)
1548 {
1549         /* execute the events */
1550         switch(event->type) {
1551                         
1552                 case MOUSEMOVE:
1553                         {
1554                                 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1555                                 ScrArea *sa = screen_areahascursor(C->screen, event->x, event->y);
1556                                 if((jd->sa1 != sa) && (jd->sa2 != sa))
1557                                 {
1558                                         printf("New Area \n");
1559                                         jd->sa2 = sa;
1560                                 }
1561                                 break;
1562                         }
1563                 case RIGHTMOUSE:
1564                         if(event->val==0) {
1565                                 join_areas_exec(C, op);
1566                                 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1567                                 join_areas_exit(C, op);
1568                                 WM_event_remove_modal_handler(&C->window->handlers, op);
1569                         }
1570                         break;
1571                         
1572                 case ESCKEY:
1573                         op->delta= 0;
1574                         join_areas_exit(C, op);
1575                         WM_event_remove_modal_handler(&C->window->handlers, op);                        
1576                         break;
1577         }
1578         return 1;
1579 }
1580
1581 /* Operator for joining two areas (space types) */
1582 void ED_SCR_OT_join_areas(wmOperatorType *ot)
1583 {
1584         
1585         /* identifiers */
1586         ot->name= "Join area";
1587         ot->idname= "ED_SCR_OT_join_areas";
1588         
1589         /* api callbacks */
1590         ot->init= join_areas_init;
1591         ot->invoke= join_areas_invoke;
1592         ot->modal= join_areas_modal;
1593         ot->exec= join_areas_exec;
1594         ot->exit= join_areas_exit;
1595
1596         ot->poll= ED_operator_screenactive;
1597 }