1f0bd66062c0a15851b7015e9560920baf1c0ba1
[blender-staging.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
31 #include "BKE_global.h"
32 #include "BKE_library.h"
33 #include "BKE_main.h"
34 #include "BKE_screen.h"
35 #include "BKE_utildefines.h"
36
37 #include "BIF_gl.h"
38 #include "BIF_glutil.h"
39 #include "BIF_resources.h"
40
41 #include "WM_api.h"
42 #include "WM_types.h"
43
44 #include "ED_area.h"
45 #include "ED_screen.h"
46
47 #include "wm_subwindow.h"
48
49 #include "screen_intern.h"      /* own module include */
50
51 /* ******************* screen vert, edge, area managing *********************** */
52
53 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
54 {
55         ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
56         sv->vec.x= x;
57         sv->vec.y= y;
58         
59         BLI_addtail(&sc->vertbase, sv);
60         return sv;
61 }
62
63 static void sortscrvert(ScrVert **v1, ScrVert **v2)
64 {
65         ScrVert *tmp;
66         
67         if (*v1 > *v2) {
68                 tmp= *v1;
69                 *v1= *v2;
70                 *v2= tmp;       
71         }
72 }
73
74 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
75 {
76         ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
77         
78         sortscrvert(&v1, &v2);
79         se->v1= v1;
80         se->v2= v2;
81         
82         BLI_addtail(&sc->edgebase, se);
83         return se;
84 }
85
86
87 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
88 {
89         ScrEdge *se;
90         
91         sortscrvert(&v1, &v2);
92         for (se= sc->edgebase.first; se; se= se->next)
93                 if(se->v1==v1 && se->v2==v2)
94                         return se;
95         
96         return NULL;
97 }
98
99 static ScrArea *screen_test_edge_area(bScreen* scr, ScrArea *sa, ScrEdge *se)
100 {
101         /* test if edge is in area, if not, 
102            then find an area that has it */
103   
104         ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
105         
106         if(sa) {
107         se1= screen_findedge(scr, sa->v1, sa->v2);
108                 se2= screen_findedge(scr, sa->v2, sa->v3);
109         se3= screen_findedge(scr, sa->v3, sa->v4);
110                 se4= screen_findedge(scr, sa->v4, sa->v1);
111         }
112         if(se1!=se && se2!=se && se3!=se && se4!=se) {
113                 
114                 sa= scr->areabase.first;
115                 while(sa) {
116                                 /* a bit optimise? */
117                                 if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
118                                 se1= screen_findedge(scr, sa->v1, sa->v2);
119                                         se2= screen_findedge(scr, sa->v2, sa->v3);
120                                         se3= screen_findedge(scr, sa->v3, sa->v4);
121                                         se4= screen_findedge(scr, sa->v4, sa->v1);
122                                         if(se1==se || se2==se || se3==se || se4==se) return sa;
123                                 }
124                                 sa= sa->next;
125                         }
126         }
127
128         return sa;      /* is null when not find */
129 }
130
131 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
132 {
133         ScrArea *sa= NULL;
134         sa= scr->areabase.first;
135         while(sa) {
136                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
137                 sa= sa->next;
138         }
139
140         return sa;
141 }
142
143 static void removedouble_scrverts(bScreen *sc)
144 {
145         ScrVert *v1, *verg;
146         ScrEdge *se;
147         ScrArea *sa;
148         
149         verg= sc->vertbase.first;
150         while(verg) {
151                 if(verg->newv==NULL) {  /* !!! */
152                         v1= verg->next;
153                         while(v1) {
154                                 if(v1->newv==NULL) {    /* !?! */
155                                         if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
156                                                 /* printf("doublevert\n"); */
157                                                 v1->newv= verg;
158                                         }
159                                 }
160                                 v1= v1->next;
161                         }
162                 }
163                 verg= verg->next;
164         }
165
166         /* replace pointers in edges and faces */
167         se= sc->edgebase.first;
168         while(se) {
169                 if(se->v1->newv) se->v1= se->v1->newv;
170                 if(se->v2->newv) se->v2= se->v2->newv;
171                 /* edges changed: so.... */
172                 sortscrvert(&(se->v1), &(se->v2));
173                 se= se->next;
174         }
175         sa= sc->areabase.first;
176         while(sa) {
177                 if(sa->v1->newv) sa->v1= sa->v1->newv;
178                 if(sa->v2->newv) sa->v2= sa->v2->newv;
179                 if(sa->v3->newv) sa->v3= sa->v3->newv;
180                 if(sa->v4->newv) sa->v4= sa->v4->newv;
181                 sa= sa->next;
182         }
183
184         /* remove */
185         verg= sc->vertbase.first;
186         while(verg) {
187                 v1= verg->next;
188                 if(verg->newv) {
189                         BLI_remlink(&sc->vertbase, verg);
190                         MEM_freeN(verg);
191                 }
192                 verg= v1;
193         }
194
195 }
196
197 static void removenotused_scrverts(bScreen *sc)
198 {
199         ScrVert *sv, *svn;
200         ScrEdge *se;
201         
202         /* we assume edges are ok */
203         
204         se= sc->edgebase.first;
205         while(se) {
206                 se->v1->flag= 1;
207                 se->v2->flag= 1;
208                 se= se->next;
209         }
210         
211         sv= sc->vertbase.first;
212         while(sv) {
213                 svn= sv->next;
214                 if(sv->flag==0) {
215                         BLI_remlink(&sc->vertbase, sv);
216                         MEM_freeN(sv);
217                 }
218                 else sv->flag= 0;
219                 sv= svn;
220         }
221 }
222
223 static void removedouble_scredges(bScreen *sc)
224 {
225         ScrEdge *verg, *se, *sn;
226         
227         /* compare */
228         verg= sc->edgebase.first;
229         while(verg) {
230                 se= verg->next;
231                 while(se) {
232                         sn= se->next;
233                         if(verg->v1==se->v1 && verg->v2==se->v2) {
234                                 BLI_remlink(&sc->edgebase, se);
235                                 MEM_freeN(se);
236                         }
237                         se= sn;
238                 }
239                 verg= verg->next;
240         }
241 }
242
243 static void removenotused_scredges(bScreen *sc)
244 {
245         ScrEdge *se, *sen;
246         ScrArea *sa;
247         int a=0;
248         
249         /* sets flags when edge is used in area */
250         sa= sc->areabase.first;
251         while(sa) {
252                 se= screen_findedge(sc, sa->v1, sa->v2);
253                 if(se==0) printf("error: area %d edge 1 bestaat niet\n", a);
254                 else se->flag= 1;
255                 se= screen_findedge(sc, sa->v2, sa->v3);
256                 if(se==0) printf("error: area %d edge 2 bestaat niet\n", a);
257                 else se->flag= 1;
258                 se= screen_findedge(sc, sa->v3, sa->v4);
259                 if(se==0) printf("error: area %d edge 3 bestaat niet\n", a);
260                 else se->flag= 1;
261                 se= screen_findedge(sc, sa->v4, sa->v1);
262                 if(se==0) printf("error: area %d edge 4 bestaat niet\n", a);
263                 else se->flag= 1;
264                 sa= sa->next;
265                 a++;
266         }
267         se= sc->edgebase.first;
268         while(se) {
269                 sen= se->next;
270                 if(se->flag==0) {
271                         BLI_remlink(&sc->edgebase, se);
272                         MEM_freeN(se);
273                 }
274                 else se->flag= 0;
275                 se= sen;
276         }
277 }
278
279 static int scredge_is_horizontal(ScrEdge *se)
280 {
281         return (se->v1->vec.y == se->v2->vec.y);
282 }
283
284 static ScrEdge *screen_find_active_scredge(bScreen *sc, int mx, int my)
285 {
286         ScrEdge *se;
287         
288         for (se= sc->edgebase.first; se; se= se->next) {
289                 if (scredge_is_horizontal(se)) {
290                         short min, max;
291                         min= MIN2(se->v1->vec.x, se->v2->vec.x);
292                         max= MAX2(se->v1->vec.x, se->v2->vec.x);
293                         
294                         if (abs(my-se->v1->vec.y)<=2 && mx>=min && mx<=max)
295                                 return se;
296                 } 
297                 else {
298                         short min, max;
299                         min= MIN2(se->v1->vec.y, se->v2->vec.y);
300                         max= MAX2(se->v1->vec.y, se->v2->vec.y);
301                         
302                         if (abs(mx-se->v1->vec.x)<=2 && my>=min && my<=max)
303                                 return se;
304                 }
305         }
306         
307         return NULL;
308 }
309
310 /* danger: is used while areamove! */
311 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
312 {
313         ScrEdge *se;
314         ScrVert *sv;
315         int oneselected;
316         char dir;
317         
318         /* select connected, only in the right direction */
319         /* 'dir' is the direction of EDGE */
320         
321         if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
322         else dir= 'h';
323         
324         sv= sc->vertbase.first;
325         while(sv) {
326                 sv->flag = 0;
327                 sv= sv->next;
328         }
329         
330         edge->v1->flag= 1;
331         edge->v2->flag= 1;
332         
333         oneselected= 1;
334         while(oneselected) {
335                 se= sc->edgebase.first;
336                 oneselected= 0;
337                 while(se) {
338                         if(se->v1->flag + se->v2->flag==1) {
339                                 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
340                                         se->v1->flag= se->v2->flag= 1;
341                                         oneselected= 1;
342                                 }
343                                 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
344                                         se->v1->flag= se->v2->flag= 1;
345                                         oneselected= 1;
346                                 }
347                         }
348                         se= se->next;
349                 }
350         }
351 }
352
353 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
354 {
355         ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
356         sa->v1= v1;
357         sa->v2= v2;
358         sa->v3= v3;
359         sa->v4= v4;
360         sa->headertype= headertype;
361         sa->spacetype= spacetype;
362         
363         BLI_addtail(&sc->areabase, sa);
364         
365         return sa;
366 }
367
368 static void screen_delarea(bScreen *sc, ScrArea *sa)
369 {       
370         BKE_screen_area_free(sa);
371         BLI_remlink(&sc->areabase, sa);
372         MEM_freeN(sa);
373 }
374
375 bScreen *addscreen(wmWindow *win, char *name)
376 {
377         bScreen *sc;
378         ScrVert *sv1, *sv2, *sv3, *sv4;
379         
380         sc= alloc_libblock(&G.main->screen, ID_SCR, name);
381         
382         sc->scene= G.scene;
383         
384         sv1= screen_addvert(sc, 0, 0);
385         sv2= screen_addvert(sc, 0, win->sizey-1);
386         sv3= screen_addvert(sc, win->sizex-1, win->sizey-1);
387         sv4= screen_addvert(sc, win->sizex-1, 0);
388         
389         screen_addedge(sc, sv1, sv2);
390         screen_addedge(sc, sv2, sv3);
391         screen_addedge(sc, sv3, sv4);
392         screen_addedge(sc, sv4, sv1);
393         
394         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_INFO);
395                 
396         return sc;
397 }
398
399
400 static void screen_copy(bScreen *to, bScreen *from)
401 {
402         ScrVert *s1, *s2;
403         ScrEdge *se;
404         ScrArea *sa, *saf;
405         
406         /* free contents of 'to', is from blenkernel screen.c */
407         free_screen(to);
408         
409         BLI_duplicatelist(&to->vertbase, &from->vertbase);
410         BLI_duplicatelist(&to->edgebase, &from->edgebase);
411         BLI_duplicatelist(&to->areabase, &from->areabase);
412         
413         s2= to->vertbase.first;
414         for(s1= from->vertbase.first; s1; s1= s1->next, s2= s2->next) {
415                 s1->newv= s2;
416         }
417         
418         for(se= to->edgebase.first; se; se= se->next) {
419                 se->v1= se->v1->newv;
420                 se->v2= se->v2->newv;
421                 sortscrvert(&(se->v1), &(se->v2));
422         }
423         
424         saf= from->areabase.first;
425         for(sa= to->areabase.first; sa; sa= sa->next, saf= saf->next) {
426                 sa->v1= sa->v1->newv;
427                 sa->v2= sa->v2->newv;
428                 sa->v3= sa->v3->newv;
429                 sa->v4= sa->v4->newv;
430                 
431                 sa->spacedata.first= sa->spacedata.last= NULL;
432                 sa->uiblocks.first= sa->uiblocks.last= NULL;
433                 sa->panels.first= sa->panels.last= NULL;
434                 sa->regionbase.first= sa->regionbase.last= NULL;
435                 sa->scriptlink.totscript= 0;
436                 
437                 area_copy_data(sa, saf, 0);
438         }
439         
440         /* put at zero (needed?) */
441         for(s1= from->vertbase.first; s1; s1= s1->next)
442                 s1->newv= NULL;
443
444 }
445
446 bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
447 {
448         bScreen *newsc;
449         
450         if(sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
451         
452         /* make new screen: */
453         newsc= addscreen(win, sc->id.name+2);
454         /* copy all data */
455         screen_copy(newsc, sc);
456         
457         return newsc;
458 }
459
460 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
461 /* used with split operator */
462 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
463 {
464         ScrVert *sav1= sa->v1;
465         ScrVert *sav2= sa->v2;
466         ScrVert *sav3= sa->v3;
467         ScrVert *sav4= sa->v4;
468         ScrVert *sbv1= sb->v1;
469         ScrVert *sbv2= sb->v2;
470         ScrVert *sbv3= sb->v3;
471         ScrVert *sbv4= sb->v4;
472         
473         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
474                 return screen_findedge(screen, sav1, sav2);
475         }
476         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
477                 return screen_findedge(screen, sav2, sav3);
478         }
479         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
480                 return screen_findedge(screen, sav3, sav4);
481         }
482         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
483                 return screen_findedge(screen, sav1, sav4);
484         }
485         
486         return NULL;
487 }
488
489 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
490 /* -1 = not valid check */
491 /* used with split operator */
492 static int area_getorientation(bScreen *screen, ScrArea *sa, ScrArea *sb)
493 {
494         ScrVert *sav1= sa->v1;
495         ScrVert *sav2= sa->v2;
496         ScrVert *sav3= sa->v3;
497         ScrVert *sav4= sa->v4;
498         ScrVert *sbv1= sb->v1;
499         ScrVert *sbv2= sb->v2;
500         ScrVert *sbv3= sb->v3;
501         ScrVert *sbv4= sb->v4;
502         
503         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
504                 return 0;
505         }
506         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
507                 return 1;
508         }
509         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
510                 return 2;
511         }
512         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
513                 return 3;
514         }
515         
516         return -1;
517 }
518
519 /* return 0: no split possible */
520 /* else return (integer) screencoordinate split point */
521 static short testsplitpoint(wmWindow *win, ScrArea *sa, char dir, float fac)
522 {
523         short x, y;
524         
525         // area big enough?
526         if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
527         if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
528
529         // to be sure
530         if(fac<0.0) fac= 0.0;
531         if(fac>1.0) fac= 1.0;
532         
533         if(dir=='h') {
534                 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
535                 
536                 //XXX G.curscreen!
537                 if(sa->v2->vec.y==win->sizey-1 && sa->v2->vec.y- y < HEADERY) 
538                         y= sa->v2->vec.y- HEADERY;
539
540                 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
541                         y= sa->v1->vec.y+ HEADERY;
542
543                 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
544                 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
545                 else y-= (y % AREAGRID);
546
547                 return y;
548         }
549         else {
550                 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
551                 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
552                 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
553                 else x-= (x % AREAGRID);
554
555                 return x;
556         }
557 }
558
559 static ScrArea* splitarea(wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac)
560 {
561         ScrArea *newa=NULL;
562         ScrVert *sv1, *sv2;
563         short split;
564         
565         if(sa==0) return NULL;
566         
567         split= testsplitpoint(win, sa, dir, fac);
568         if(split==0) return NULL;
569         
570         //sc= G.curscreen;
571         
572         //areawinset(sa->win);
573         
574         if(dir=='h') {
575                 /* new vertices */
576                 sv1= screen_addvert(sc, sa->v1->vec.x, split);
577                 sv2= screen_addvert(sc, sa->v4->vec.x, split);
578                 
579                 /* new edges */
580                 screen_addedge(sc, sa->v1, sv1);
581                 screen_addedge(sc, sv1, sa->v2);
582                 screen_addedge(sc, sa->v3, sv2);
583                 screen_addedge(sc, sv2, sa->v4);
584                 screen_addedge(sc, sv1, sv2);
585                 
586                 /* new areas: top */
587                 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
588                 area_copy_data(newa, sa, 0);
589
590                 /* area below */
591                 sa->v2= sv1;
592                 sa->v3= sv2;
593                 
594         }
595         else {
596                 /* new vertices */
597                 sv1= screen_addvert(sc, split, sa->v1->vec.y);
598                 sv2= screen_addvert(sc, split, sa->v2->vec.y);
599                 
600                 /* new edges */
601                 screen_addedge(sc, sa->v1, sv1);
602                 screen_addedge(sc, sv1, sa->v4);
603                 screen_addedge(sc, sa->v2, sv2);
604                 screen_addedge(sc, sv2, sa->v3);
605                 screen_addedge(sc, sv1, sv2);
606                 
607                 /* new areas: left */
608                 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
609                 area_copy_data(newa, sa, 0);
610
611                 /* area right */
612                 sa->v1= sv1;
613                 sa->v2= sv2;
614         }
615         
616         /* remove double vertices en edges */
617         removedouble_scrverts(sc);
618         removedouble_scredges(sc);
619         removenotused_scredges(sc);
620         
621         return newa;
622 }
623
624
625 /* *************************************************************** */
626
627 /* test if screen vertices should be scaled */
628 void screen_test_scale(bScreen *sc, int winsizex, int winsizey)
629 {
630         ScrVert *sv=NULL;
631         ScrArea *sa, *san;
632         int sizex, sizey;
633         float facx, facy, tempf, min[2], max[2];
634         
635         /* calculate size */
636         min[0]= min[1]= 10000.0f;
637         max[0]= max[1]= 0.0f;
638         
639         for(sv= sc->vertbase.first; sv; sv= sv->next) {
640                 min[0]= MIN2(min[0], sv->vec.x);
641                 min[1]= MIN2(min[1], sv->vec.y);
642                 max[0]= MAX2(max[0], sv->vec.x);
643                 max[1]= MAX2(max[1], sv->vec.y);
644         }
645         
646         /* always make 0.0 left under */
647         for(sv= sc->vertbase.first; sv; sv= sv->next) {
648                 sv->vec.x -= min[0];
649                 sv->vec.y -= min[1];
650         }
651         
652         sizex= max[0]-min[0];
653         sizey= max[1]-min[1];
654         
655         if(sizex!= winsizex || sizey!= winsizey) {
656                 facx= winsizex;
657                 facx/= (float)sizex;
658                 facy= winsizey;
659                 facy/= (float)sizey;
660                 
661                 /* make sure it fits! */
662                 for(sv= sc->vertbase.first; sv; sv= sv->next) {
663                         tempf= ((float)sv->vec.x)*facx;
664                         sv->vec.x= (short)(tempf+0.5);
665                         sv->vec.x+= AREAGRID-1;
666                         sv->vec.x-=  (sv->vec.x % AREAGRID); 
667                         
668                         CLAMP(sv->vec.x, 0, winsizex);
669                         
670                         tempf= ((float)sv->vec.y )*facy;
671                         sv->vec.y= (short)(tempf+0.5);
672                         sv->vec.y+= AREAGRID-1;
673                         sv->vec.y-=  (sv->vec.y % AREAGRID); 
674                         
675                         CLAMP(sv->vec.y, 0, winsizey);
676                 }
677         }
678         
679         /* test for collapsed areas. This could happen in some blender version... */
680         for(sa= sc->areabase.first; sa; sa= san) {
681                 san= sa->next;
682                 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3) {
683                         BKE_screen_area_free(sa);
684                         BLI_remlink(&sc->areabase, sa);
685                         MEM_freeN(sa);
686                 }
687         }
688 }
689
690
691
692 #define SCR_BACK 0.55
693 #define SCR_ROUND 12
694
695 static void drawscredge_area(ScrArea *sa)
696 {
697         short x1= sa->v1->vec.x;
698         short y1= sa->v1->vec.y;
699         short x2= sa->v3->vec.x;
700         short y2= sa->v3->vec.y;
701         
702         cpack(0x0);
703         
704         /* right border area */
705         sdrawline(x2, y1, x2, y2);
706         
707         /* left border area */
708         if(x1>0) { // otherwise it draws the emboss of window over
709                 sdrawline(x1, y1, x1, y2);
710         }       
711         /* top border area */
712         sdrawline(x1, y2, x2, y2);
713         
714         /* bottom border area */
715         sdrawline(x1, y1, x2, y1);
716 }
717
718 void ED_screen_do_listen(bScreen *screen, wmNotifier *note)
719 {
720         
721         /* generic notes */
722         switch(note->type) {
723                 case WM_NOTE_WINDOW_REDRAW:
724                         screen->do_draw= 1;
725                         break;
726                 case WM_NOTE_SCREEN_CHANGED:
727                         screen->do_draw= screen->do_refresh= 1;
728                         break;
729         }
730 }
731
732
733 void ED_screen_draw(wmWindow *win)
734 {
735         ScrArea *sa;
736         
737         wm_subwindow_set(win, win->screen->mainwin);
738         
739         for(sa= win->screen->areabase.first; sa; sa= sa->next)
740                 drawscredge_area(sa);
741
742         printf("draw screen\n");
743         win->screen->do_draw= 0;
744 }
745
746 /* make this screen usable */
747 /* for file read and first use, for scaling window, area moves */
748 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
749 {
750         ScrArea *sa;
751         rcti winrct= {0, win->sizex, 0, win->sizey};
752         
753         screen_test_scale(win->screen, win->sizex, win->sizey);
754         
755         if(win->screen->mainwin==0)
756                 win->screen->mainwin= wm_subwindow_open(win, &winrct);
757         else
758                 wm_subwindow_position(win, win->screen->mainwin, &winrct);
759         
760         for(sa= win->screen->areabase.first; sa; sa= sa->next) {
761                 /* set spacetype and region callbacks */
762                 /* sets subwindow */
763                 ED_area_initialize(wm, win, sa);
764         }
765         
766         printf("set screen\n");
767         win->screen->do_refresh= 0;
768
769 }
770
771 /* file read, set all screens, ... */
772 void ED_screens_initialize(wmWindowManager *wm)
773 {
774         wmWindow *win;
775         
776         for(win= wm->windows.first; win; win= win->next) {
777                 
778                 if(win->screen==NULL)
779                         win->screen= G.main->screen.first;
780                 
781                 ED_screen_refresh(wm, win);
782         }
783 }
784
785 void placeholder()
786 {
787         removenotused_scrverts(NULL);
788         removenotused_scredges(NULL);
789 }
790
791 /* called in wm_event_system.c. sets state var in screen */
792 void ED_screen_set_subwinactive(wmWindow *win)
793 {
794         if(win->screen) {
795                 wmEvent *event= win->eventstate;
796                 ScrArea *sa;
797                 
798                 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
799                         if(event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
800                                 if(event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
801                                         break;
802                 }
803                 if(sa) {
804                         ARegion *ar;
805                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
806                                 if(BLI_in_rcti(&ar->winrct, event->x, event->y))
807                                         win->screen->subwinactive= ar->swinid;
808                         }
809                 }
810                 else
811                         win->screen->subwinactive= win->screen->mainwin;
812                 
813         }
814 }
815
816 /* ****************** cursor near edge operator ********************************* */
817
818 /* operator cb */
819 int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event)
820 {
821         if (C->screen->subwinactive==C->screen->mainwin) {
822                 ScrEdge *actedge= screen_find_active_scredge(C->screen, event->x, event->y);
823                 
824                 if (actedge && scredge_is_horizontal(actedge)) {
825                         WM_set_cursor(C, CURSOR_Y_MOVE);
826                 } else {
827                         WM_set_cursor(C, CURSOR_X_MOVE);
828                 }
829         } else {
830                 WM_set_cursor(C, CURSOR_STD);
831         }
832         
833         return 1;
834 }
835
836 /* ************** move area edge operator ********************************************** */
837
838 /* operator state vars used:  
839            op->veci   mouse coord near edge
840            op->delta  movement of edge
841
842    callbacks:
843
844    init()   find edge based on op->veci, test if the edge can be moved, select edges,
845             clear delta, calculate min and max movement
846
847    exec()       apply op->delta on selection
848    
849    invoke() handler gets called on a mouse click near edge
850             call init()
851             add handler
852
853    modal()      accept modal events while doing it
854                         call exec() with delta motion
855             call exit() and remove handler
856
857    exit()       cleanup, send notifier
858
859 */
860
861 /* validate selection inside screen, set variables OK */
862 /* return 0: init failed */
863 static int move_areas_init (bContext *C, wmOperator *op)
864 {
865         ScrEdge *actedge= screen_find_active_scredge(C->screen, op->veci.x, op->veci.y);
866         ScrArea *sa;
867         int bigger, smaller, dir, origval;
868         
869         if(actedge==NULL) return 0;
870         printf("move_areas_init\n");
871         
872         dir= scredge_is_horizontal(actedge)?'h':'v';
873         if(dir=='h') origval= actedge->v1->vec.y;
874         else origval= actedge->v1->vec.x;
875         
876         select_connected_scredge(C->screen, actedge);
877
878         /* now all verices with 'flag==1' are the ones that can be moved. */
879         /* we check all areas and test for free space with MINSIZE */
880         bigger= smaller= 10000;
881         for(sa= C->screen->areabase.first; sa; sa= sa->next) {
882                 if(dir=='h') {  /* if top or down edge selected, test height */
883                    
884                    if(sa->v1->flag && sa->v4->flag) {
885                            int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
886                            bigger= MIN2(bigger, y1);
887                    }
888                    else if(sa->v2->flag && sa->v3->flag) {
889                            int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
890                            smaller= MIN2(smaller, y1);
891                    }
892                 }
893                 else {  /* if left or right edge selected, test width */
894                         if(sa->v1->flag && sa->v2->flag) {
895                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
896                                 bigger= MIN2(bigger, x1);
897                         }
898                         else if(sa->v3->flag && sa->v4->flag) {
899                                 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
900                                 smaller= MIN2(smaller, x1);
901                         }
902                 }
903         }
904
905         OP_set_int(op, "bigger", bigger);
906         OP_set_int(op, "smaller", smaller);
907         OP_set_int(op, "dir", dir);
908         OP_set_int(op, "origval", origval);
909
910         return 1;
911 }
912
913 /* moves selected screen edge amount of delta */
914 /* needs init call to work */
915 static int move_areas_exec(bContext *C, wmOperator *op)
916 {
917         ScrVert *v1;
918         int bigger, smaller, dir, origval;
919
920         OP_get_int(op, "bigger", &bigger);
921         OP_get_int(op, "smaller", &smaller);
922         OP_get_int(op, "dir", &dir);
923         OP_get_int(op, "origval", &origval);
924         
925         printf("move_areas_exec\n");
926         
927         op->delta= CLAMPIS(op->delta, -smaller, bigger);
928         
929         for (v1= C->screen->vertbase.first; v1; v1= v1->next) {
930                 if (v1->flag) {
931                         /* that way a nice AREAGRID  */
932                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<C->window->sizex-1) {
933                                 v1->vec.x= origval + op->delta;
934                                 if(op->delta != bigger && op->delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
935                         }
936                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<C->window->sizey-1) {
937                                 v1->vec.y= origval + op->delta;
938
939                                 v1->vec.y+= AREAGRID-1;
940                                 v1->vec.y-= (v1->vec.y % AREAGRID);
941                                 
942                                 /* prevent too small top header */
943                                 if(v1->vec.y > C->window->sizey-HEADERY)
944                                         v1->vec.y= C->window->sizey-HEADERY;
945                         }
946                 }
947         }
948         return 1;
949 }
950
951 static int move_areas_exit(bContext *C, wmOperator *op)
952 {
953         printf("move_areas_exit\n");
954         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0);
955
956         /* this makes sure aligned edges will result in aligned grabbing */
957         removedouble_scrverts(C->screen);
958         removedouble_scredges(C->screen);
959         
960         return 1;
961 }
962
963 /* interaction callback */
964 /* return 0 = stop evaluating for next handlers */
965 static int move_areas_invoke (bContext *C, wmOperator *op, wmEvent *event)
966 {
967         
968         /* operator arguments and storage */
969         op->delta= 0;
970         op->veci.x= event->x;
971         op->veci.y= event->y;
972         
973         if(0==move_areas_init(C, op)) 
974                 return 1;
975         
976         printf("move_areas_invoke\n");
977         
978         /* add temp handler */
979         WM_event_add_modal_handler(&C->window->handlers, op);
980         
981         return 0;
982 }
983
984 /* modal callback for while moving edges */
985 /* return 0 = stop evaluating for next handlers */
986 static int move_areas_modal (bContext *C, wmOperator *op, wmEvent *event)
987 {
988         int dir;
989
990         OP_get_int(op, "dir", &dir);
991
992         printf("move_areas_modal\n");
993         /* execute the events */
994         switch(event->type) {
995                 case MOUSEMOVE:
996                         
997                         if(dir=='v')
998                                 op->delta= event->x - op->veci.x;
999                         else
1000                                 op->delta= event->y - op->veci.y;
1001                         
1002                         move_areas_exec(C, op);
1003                         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0);
1004                         break;
1005                         
1006                 case LEFTMOUSE:
1007                         if(event->val==0) {
1008                                 WM_event_remove_modal_handler(&C->window->handlers, op);
1009                                 move_areas_exit(C, op);
1010                         }
1011                         break;
1012                         
1013                 case ESCKEY:
1014                         op->delta= 0;
1015                         move_areas_exec(C, op);
1016                         
1017                         WM_event_remove_modal_handler(&C->window->handlers, op);
1018                         move_areas_exit(C, op);
1019                         break;
1020         }
1021         
1022         return 1;
1023 }
1024
1025 void ED_SCR_OT_move_areas(wmOperatorType *ot)
1026 {
1027         
1028         /* identifiers */
1029         ot->name= "Move area edges";
1030         ot->idname= "ED_SCR_OT_move_areas";
1031
1032         ot->init= move_areas_init;
1033         ot->invoke= move_areas_invoke;
1034         ot->modal= move_areas_modal;
1035         ot->exec= move_areas_exec;
1036         ot->exit= move_areas_exit;
1037
1038         ot->poll= ED_operator_screen_mainwinactive;
1039 }
1040
1041 /****************** split area ********************/
1042 /* we do split on init, then we work like move_areas
1043         if operation gets cancelled -> join
1044         if operation gets confirmed -> yay
1045 */
1046
1047 typedef struct sAreaSplitData
1048 {
1049         int dir; /* direction of new edge */
1050         int origval; /* for move areas */
1051         int min,max; /* constraints for moving new edge */
1052         int pos; /* with sa as center, ne is located at: 0=W, 1=N, 2=E, 3=S */
1053         ScrEdge *nedge; /* new edge */
1054         ScrEdge *aedge;
1055         ScrArea *sarea; /* start area */
1056         ScrArea *narea; /* new area */
1057 } sAreaSplitData;
1058
1059 /* the moving of the new egde */
1060 static int split_area_exec(bContext *C, wmOperator *op)
1061 {
1062         ScrVert *v1;
1063         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1064         int newval= sd->origval + op->delta;
1065         printf("split_area_exec %d %c, %d %d, %d", op->delta, sd->dir, -sd->min, sd->max, sd->origval);
1066         
1067         op->delta= CLAMPIS(op->delta, -sd->min, sd->max);
1068         
1069         
1070         printf(".");
1071         /* that way a nice AREAGRID  */
1072         if((sd->dir=='v') && (newval > sd->min && newval < sd->max-1)) {
1073                 sd->nedge->v1->vec.x= newval;
1074                 sd->nedge->v2->vec.x= newval;
1075                 //if(op->delta != sd->max && op->delta != -sd->min) v1->vec.x-= (v1->vec.x % AREAGRID);
1076         }
1077         if((sd->dir=='h') && (newval > sd->min+HEADERY && newval < sd->max-HEADERY)) {
1078                 sd->nedge->v1->vec.y= sd->origval + op->delta;
1079                 sd->nedge->v1->vec.y+= AREAGRID-1;
1080                 sd->nedge->v1->vec.y-= (sd->nedge->v1->vec.y % AREAGRID);
1081                 if(sd->nedge->v1->vec.y > C->window->sizey-HEADERY)
1082                         sd->nedge->v1->vec.y= C->window->sizey-HEADERY;
1083                 
1084                 sd->nedge->v2->vec.y= sd->origval + op->delta;
1085                 sd->nedge->v2->vec.y+= AREAGRID-1;
1086                 sd->nedge->v2->vec.y-= (sd->nedge->v2->vec.y % AREAGRID);
1087                 if(sd->nedge->v2->vec.y > C->window->sizey-HEADERY)
1088                         sd->nedge->v2->vec.y= C->window->sizey-HEADERY;
1089         }
1090         printf("\n");
1091         return 1;
1092 }
1093
1094 static int split_area_exit(bContext *C, wmOperator *op)
1095 {
1096         printf("split_area_exit\n");
1097         if (op->customdata) {
1098                 MEM_freeN(op->customdata);
1099                 op->customdata = NULL;
1100         }
1101         
1102         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0);
1103
1104         /* this makes sure aligned edges will result in aligned grabbing */
1105         removedouble_scrverts(C->screen);
1106         removedouble_scredges(C->screen);
1107         
1108         return 1;
1109 }
1110
1111 static void split_initintern(bContext *C, wmOperator *op, sAreaSplitData *sd)
1112 {
1113         float fac= 0.0;
1114         if(sd->dir=='h') {
1115                 sd->origval= op->veci.y;
1116                 fac= 1.0 - ((float)(sd->sarea->v3->vec.y - op->veci.y)) / (float)sd->sarea->winy;
1117                 sd->min= sd->aedge->v1->vec.y;
1118                 sd->max= sd->aedge->v2->vec.y;
1119         }
1120         else {
1121                 sd->origval= op->veci.x;
1122                 fac= 1.0 - ((float)(sd->sarea->v4->vec.x - op->veci.x)) / (float)sd->sarea->winx;
1123                 sd->min= sd->aedge->v1->vec.x;
1124                 sd->max= sd->aedge->v2->vec.x;
1125         }
1126         
1127         sd->narea= splitarea(C->window, C->screen, sd->sarea, sd->dir, fac);
1128         sd->nedge= area_findsharededge(C->screen, sd->sarea, sd->narea);
1129         
1130         printf("split_area_init\n");
1131         /* get newly created edge and select it */
1132         select_connected_scredge(C->screen, sd->nedge);
1133         
1134 }
1135
1136 static int split_area_init (bContext *C, wmOperator *op)
1137 {
1138         float fac= 0.0;
1139         sAreaSplitData *sd= NULL;
1140         ScrEdge *actedge= screen_find_active_scredge(C->screen, op->veci.x, op->veci.y);
1141         
1142         if(actedge==NULL) return 0;
1143         
1144         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_split_area");
1145         op->customdata= sd;
1146         /* for split dir is in which new edge comes */
1147         sd->dir= scredge_is_horizontal(actedge) ? 'v':'h';
1148         sd->sarea= screen_test_edge_area(C->screen, C->curarea, actedge);
1149         sd->aedge= actedge;
1150
1151         split_initintern(C, op, sd);
1152         if(sd->narea == NULL) return 0;
1153         
1154         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0);
1155
1156         return 1;
1157 }
1158
1159 static int split_area_invoke(bContext *C, wmOperator *op, wmEvent *event)
1160 {
1161         /* operator arguments and storage */
1162         op->delta= 0;
1163         op->veci.x= event->x;
1164         op->veci.y= event->y;
1165         
1166         if(0==split_area_init(C, op)) 
1167                 return 1;
1168         
1169         printf("split_area_invoke %d %d %d\n", op->delta, op->veci.x, op->veci.y);
1170         
1171         /* add temp handler */
1172         WM_event_add_modal_handler(&C->window->handlers, op);
1173         
1174         return 0;
1175 }
1176
1177 static void split_joincurrent(bContext *C, sAreaSplitData *sd)
1178 {
1179         int orientation= area_getorientation(C->window->screen, sd->sarea, sd->narea);
1180         if(orientation>-1) {
1181                 if(orientation==0) {
1182                         sd->sarea->v1= sd->narea->v1;
1183                         sd->sarea->v2= sd->narea->v2;
1184                         screen_addedge(C->screen, sd->sarea->v2, sd->sarea->v3);
1185                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v4);
1186                 }
1187                 else if(orientation==1) {
1188                         sd->sarea->v2= sd->narea->v2;
1189                         sd->sarea->v3= sd->narea->v3;
1190                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v2);
1191                         screen_addedge(C->screen, sd->sarea->v3, sd->sarea->v4);
1192                 }
1193                 else if(orientation==2) {
1194                         sd->sarea->v3= sd->narea->v3;
1195                         sd->sarea->v4= sd->narea->v4;
1196                         screen_addedge(C->screen, sd->sarea->v2,sd-> sarea->v3);
1197                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v4);
1198                 }
1199                 else if(orientation==3) {
1200                         sd->sarea->v1= sd->narea->v1;
1201                         sd->sarea->v4= sd->narea->v4;
1202                         screen_addedge(C->screen, sd->sarea->v1, sd->sarea->v2);
1203                         screen_addedge(C->screen, sd->sarea->v3, sd->sarea->v4);
1204                 }
1205
1206                 if (C->curarea == sd->narea) {
1207                         C->curarea = NULL;
1208                 }
1209                 screen_delarea(C->screen, sd->narea);
1210                 sd->narea = NULL;
1211                 removedouble_scrverts(C->screen);
1212                 removedouble_scredges(C->screen);
1213         }
1214 }
1215
1216 static int split_area_modal(bContext *C, wmOperator *op, wmEvent *event)
1217 {
1218         ScrArea *sa= NULL, *sold=NULL;
1219         int orientation= -1;
1220         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1221         printf("split_area_modal\n");
1222         /* execute the events */
1223         switch(event->type) {
1224                 case MOUSEMOVE:
1225
1226                         sa= screen_areahascursor(C->screen, event->x, event->y);
1227
1228                         if(sa && sd->sarea!=sa && sd->narea!=sa) {
1229                                 sold= sd->sarea;
1230                                 printf("In other area now\n");
1231                                 split_joincurrent(C, sd);
1232                                 //sd->aedge= area_findsharededge(C->screen, sold, sa);
1233                                 /* now find aedge with same orientation as sd->dir (inverted) */
1234                                 if(sd->dir=='v') sd->aedge= screen_findedge(C->screen, sa->v1, sa->v4);
1235                                 else sd->aedge= screen_findedge(C->screen, sa->v1, sa->v2);
1236                                 sd->sarea= sa;
1237                                 op->delta= 0;
1238                                 op->veci.x= event->x;
1239                                 op->veci.y= event->y;
1240                                 split_initintern(C, op, sd);
1241                         }
1242                         else {
1243                                 if(sd->dir=='v')
1244                                         op->delta= event->x - op->veci.x;
1245                                 else
1246                                         op->delta= event->y - op->veci.y;
1247                                 
1248                                 split_area_exec(C, op);
1249                         }
1250                         WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0);
1251                         break;
1252                         
1253                 case RIGHTMOUSE:
1254                         if(event->val==0) { /* mouse up */
1255                                 WM_event_remove_modal_handler(&C->window->handlers, op);
1256                                 split_area_exit(C, op);
1257                         }
1258                         break;
1259                         
1260                 case LEFTMOUSE:
1261                 case ESCKEY:
1262                         op->delta= 0;
1263                         split_joincurrent(C, sd);
1264                         WM_event_remove_modal_handler(&C->window->handlers, op);
1265                         split_area_exit(C, op);
1266                         break;
1267         }
1268         
1269         return 1;
1270 }
1271
1272 void ED_SCR_OT_split_area(wmOperatorType *ot)
1273 {
1274         ot->name = "Split area";
1275         ot->idname = "ED_SCR_OT_split_area";
1276         
1277         ot->init= split_area_init;
1278         ot->invoke= split_area_invoke;
1279         ot->modal= split_area_modal;
1280         ot->exec= NULL;//split_area_exec;
1281         ot->exit= split_area_exit;
1282         
1283         ot->poll= ED_operator_screenactive;
1284         //ot->poll= ED_operator_screen_mainwinactive;
1285 }