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