4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * ***** END GPL LICENSE BLOCK *****
27 #include "MEM_guardedalloc.h"
29 #include "BLI_blenlib.h"
30 #include "BLI_arithb.h"
32 #include "BKE_global.h"
33 #include "BKE_library.h"
35 #include "BKE_screen.h"
36 #include "BKE_utildefines.h"
39 #include "BIF_glutil.h"
45 #include "ED_screen.h"
46 #include "ED_screen_types.h"
48 #include "wm_subwindow.h"
50 #include "screen_intern.h" /* own module include */
52 /* ******************* gesture manager ******************* */
53 void ed_gesture_draw_rect(wmWindow *win, wmGesture *gt)
55 wmGestureRect *rect= (wmGestureRect *)gt;
56 sdrawbox(rect->x1, rect->y1, rect->x2, rect->y2);
59 void ed_gesture_update(wmWindow *win)
61 wmGesture *gt= (wmGesture *)win->gesture.first;
64 if(gt->type==GESTURE_RECT)
65 ed_gesture_draw_rect(win, gt);
70 /* ******************* screen vert, edge, area managing *********************** */
72 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
74 ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
78 BLI_addtail(&sc->vertbase, sv);
82 static void sortscrvert(ScrVert **v1, ScrVert **v2)
93 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
95 ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
97 sortscrvert(&v1, &v2);
101 BLI_addtail(&sc->edgebase, se);
106 static ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
110 sortscrvert(&v1, &v2);
111 for (se= sc->edgebase.first; se; se= se->next)
112 if(se->v1==v1 && se->v2==v2)
118 static ScrArea *screen_test_edge_area(bScreen* scr, ScrArea *sa, ScrEdge *se)
120 /* test if edge is in area, if not,
121 then find an area that has it */
123 ScrEdge *se1=0, *se2=0, *se3=0, *se4=0;
126 se1= screen_findedge(scr, sa->v1, sa->v2);
127 se2= screen_findedge(scr, sa->v2, sa->v3);
128 se3= screen_findedge(scr, sa->v3, sa->v4);
129 se4= screen_findedge(scr, sa->v4, sa->v1);
131 if(se1!=se && se2!=se && se3!=se && se4!=se) {
133 sa= scr->areabase.first;
135 /* a bit optimise? */
136 if(se->v1==sa->v1 || se->v1==sa->v2 || se->v1==sa->v3 || se->v1==sa->v4) {
137 se1= screen_findedge(scr, sa->v1, sa->v2);
138 se2= screen_findedge(scr, sa->v2, sa->v3);
139 se3= screen_findedge(scr, sa->v3, sa->v4);
140 se4= screen_findedge(scr, sa->v4, sa->v1);
141 if(se1==se || se2==se || se3==se || se4==se) return sa;
147 return sa; /* is null when not find */
150 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
153 sa= scr->areabase.first;
155 if(BLI_in_rcti(&sa->totrct, x, y)) break;
162 static AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
167 for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
168 if(az && az->type == AZONE_TRI) {
169 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) break;
171 if(az->type == AZONE_QUAD) {
172 if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2) break;
179 static void removedouble_scrverts(bScreen *sc)
185 verg= sc->vertbase.first;
187 if(verg->newv==NULL) { /* !!! */
190 if(v1->newv==NULL) { /* !?! */
191 if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
192 /* printf("doublevert\n"); */
202 /* replace pointers in edges and faces */
203 se= sc->edgebase.first;
205 if(se->v1->newv) se->v1= se->v1->newv;
206 if(se->v2->newv) se->v2= se->v2->newv;
207 /* edges changed: so.... */
208 sortscrvert(&(se->v1), &(se->v2));
211 sa= sc->areabase.first;
213 if(sa->v1->newv) sa->v1= sa->v1->newv;
214 if(sa->v2->newv) sa->v2= sa->v2->newv;
215 if(sa->v3->newv) sa->v3= sa->v3->newv;
216 if(sa->v4->newv) sa->v4= sa->v4->newv;
221 verg= sc->vertbase.first;
225 BLI_remlink(&sc->vertbase, verg);
233 static void removenotused_scrverts(bScreen *sc)
238 /* we assume edges are ok */
240 se= sc->edgebase.first;
247 sv= sc->vertbase.first;
251 BLI_remlink(&sc->vertbase, sv);
259 static void removedouble_scredges(bScreen *sc)
261 ScrEdge *verg, *se, *sn;
264 verg= sc->edgebase.first;
269 if(verg->v1==se->v1 && verg->v2==se->v2) {
270 BLI_remlink(&sc->edgebase, se);
279 static void removenotused_scredges(bScreen *sc)
285 /* sets flags when edge is used in area */
286 sa= sc->areabase.first;
288 se= screen_findedge(sc, sa->v1, sa->v2);
289 if(se==0) printf("error: area %d edge 1 doesn't exist\n", a);
291 se= screen_findedge(sc, sa->v2, sa->v3);
292 if(se==0) printf("error: area %d edge 2 doesn't exist\n", a);
294 se= screen_findedge(sc, sa->v3, sa->v4);
295 if(se==0) printf("error: area %d edge 3 doesn't exist\n", a);
297 se= screen_findedge(sc, sa->v4, sa->v1);
298 if(se==0) printf("error: area %d edge 4 doesn't exist\n", a);
303 se= sc->edgebase.first;
307 BLI_remlink(&sc->edgebase, se);
315 static int scredge_is_horizontal(ScrEdge *se)
317 return (se->v1->vec.y == se->v2->vec.y);
320 static ScrEdge *screen_find_active_scredge(bScreen *sc, int mx, int my)
324 for (se= sc->edgebase.first; se; se= se->next) {
325 if (scredge_is_horizontal(se)) {
327 min= MIN2(se->v1->vec.x, se->v2->vec.x);
328 max= MAX2(se->v1->vec.x, se->v2->vec.x);
330 if (abs(my-se->v1->vec.y)<=2 && mx>=min && mx<=max)
335 min= MIN2(se->v1->vec.y, se->v2->vec.y);
336 max= MAX2(se->v1->vec.y, se->v2->vec.y);
338 if (abs(mx-se->v1->vec.x)<=2 && my>=min && my<=max)
346 /* danger: is used while areamove! */
347 static void select_connected_scredge(bScreen *sc, ScrEdge *edge)
354 /* select connected, only in the right direction */
355 /* 'dir' is the direction of EDGE */
357 if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
360 sv= sc->vertbase.first;
371 se= sc->edgebase.first;
374 if(se->v1->flag + se->v2->flag==1) {
375 if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
376 se->v1->flag= se->v2->flag= 1;
379 if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
380 se->v1->flag= se->v2->flag= 1;
389 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
391 ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
396 sa->headertype= headertype;
397 sa->spacetype= spacetype;
399 BLI_addtail(&sc->areabase, sa);
404 static void screen_delarea(bScreen *sc, ScrArea *sa)
406 /* XXX need context to cancel operators ED_area_exit(C, sa); */
407 BKE_screen_area_free(sa);
408 BLI_remlink(&sc->areabase, sa);
412 /* Helper function to join 2 areas, it has a return value, 0=failed 1=success
413 * used by the split, join and rip operators
415 int screen_join_areas(bScreen *scr, ScrArea *sa1, ScrArea *sa2);
417 static bScreen *addscreen_area(wmWindow *win, char *name, short headertype, short spacetype)
420 ScrVert *sv1, *sv2, *sv3, *sv4;
422 sc= alloc_libblock(&G.main->screen, ID_SCR, name);
426 sv1= screen_addvert(sc, 0, 0);
427 sv2= screen_addvert(sc, 0, win->sizey-1);
428 sv3= screen_addvert(sc, win->sizex-1, win->sizey-1);
429 sv4= screen_addvert(sc, win->sizex-1, 0);
431 screen_addedge(sc, sv1, sv2);
432 screen_addedge(sc, sv2, sv3);
433 screen_addedge(sc, sv3, sv4);
434 screen_addedge(sc, sv4, sv1);
436 screen_addarea(sc, sv1, sv2, sv3, sv4, headertype, spacetype);
441 static bScreen *addscreen(wmWindow *win, char *name)
443 return addscreen_area(win, name, HEADERDOWN, SPACE_INFO);
446 static void screen_copy(bScreen *to, bScreen *from)
452 /* free contents of 'to', is from blenkernel screen.c */
455 BLI_duplicatelist(&to->vertbase, &from->vertbase);
456 BLI_duplicatelist(&to->edgebase, &from->edgebase);
457 BLI_duplicatelist(&to->areabase, &from->areabase);
458 to->regionbase.first= to->regionbase.last= NULL;
460 s2= to->vertbase.first;
461 for(s1= from->vertbase.first; s1; s1= s1->next, s2= s2->next) {
465 for(se= to->edgebase.first; se; se= se->next) {
466 se->v1= se->v1->newv;
467 se->v2= se->v2->newv;
468 sortscrvert(&(se->v1), &(se->v2));
471 saf= from->areabase.first;
472 for(sa= to->areabase.first; sa; sa= sa->next, saf= saf->next) {
473 sa->v1= sa->v1->newv;
474 sa->v2= sa->v2->newv;
475 sa->v3= sa->v3->newv;
476 sa->v4= sa->v4->newv;
478 sa->spacedata.first= sa->spacedata.last= NULL;
479 sa->uiblocks.first= sa->uiblocks.last= NULL;
480 sa->panels.first= sa->panels.last= NULL;
481 sa->regionbase.first= sa->regionbase.last= NULL;
482 sa->actionzones.first= sa->actionzones.last= NULL;
483 sa->scriptlink.totscript= 0;
485 area_copy_data(sa, saf, 0);
488 /* put at zero (needed?) */
489 for(s1= from->vertbase.first; s1; s1= s1->next)
494 bScreen *ED_screen_riparea(struct wmWindow *win, bScreen *sc, struct ScrArea *sa)
500 if(sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
502 /* make new screen: */
503 newsc= addscreen_area(win, sc->id.name+2, sa->headertype, sa->spacetype);
505 /* new area is first (and only area) added to new win */
506 newa = (ScrArea *)newsc->areabase.first;
507 area_copy_data(newa, sa, 0);
509 /*remove the original area if possible*/
510 for(tsa= sc->areabase.first; tsa; tsa= tsa->next) {
511 if (screen_join_areas(sc,tsa,sa))
515 removedouble_scredges(sc);
516 removenotused_scredges(sc);
517 removenotused_scrverts(sc);
522 bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
526 if(sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
528 /* make new screen: */
529 newsc= addscreen(win, sc->id.name+2);
531 screen_copy(newsc, sc);
536 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
537 /* used with split operator */
538 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
540 ScrVert *sav1= sa->v1;
541 ScrVert *sav2= sa->v2;
542 ScrVert *sav3= sa->v3;
543 ScrVert *sav4= sa->v4;
544 ScrVert *sbv1= sb->v1;
545 ScrVert *sbv2= sb->v2;
546 ScrVert *sbv3= sb->v3;
547 ScrVert *sbv4= sb->v4;
549 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
550 return screen_findedge(screen, sav1, sav2);
552 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
553 return screen_findedge(screen, sav2, sav3);
555 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
556 return screen_findedge(screen, sav3, sav4);
558 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
559 return screen_findedge(screen, sav1, sav4);
565 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
566 /* -1 = not valid check */
567 /* used with split operator */
568 static int area_getorientation(bScreen *screen, ScrArea *sa, ScrArea *sb)
570 ScrVert *sav1, *sav2, *sav3, *sav4;
571 ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
573 if(sa==NULL || sb==NULL) return -1;
584 if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
587 else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
590 else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
593 else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
600 /* return 0: no split possible */
601 /* else return (integer) screencoordinate split point */
602 static short testsplitpoint(wmWindow *win, ScrArea *sa, char dir, float fac)
607 if(sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX) return 0;
608 if(sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY) return 0;
611 if(fac<0.0) fac= 0.0;
612 if(fac>1.0) fac= 1.0;
615 y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
617 if(sa->v2->vec.y==win->sizey-1 && sa->v2->vec.y- y < HEADERY)
618 y= sa->v2->vec.y- HEADERY;
620 else if(sa->v1->vec.y==0 && y- sa->v1->vec.y < HEADERY)
621 y= sa->v1->vec.y+ HEADERY;
623 else if(y- sa->v1->vec.y < AREAMINY) y= sa->v1->vec.y+ AREAMINY;
624 else if(sa->v2->vec.y- y < AREAMINY) y= sa->v2->vec.y- AREAMINY;
625 else y-= (y % AREAGRID);
630 x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
631 if(x- sa->v1->vec.x < AREAMINX) x= sa->v1->vec.x+ AREAMINX;
632 else if(sa->v4->vec.x- x < AREAMINX) x= sa->v4->vec.x- AREAMINX;
633 else x-= (x % AREAGRID);
639 static ScrArea* splitarea(wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac)
645 if(sa==0) return NULL;
647 split= testsplitpoint(win, sa, dir, fac);
648 if(split==0) return NULL;
652 //areawinset(sa->win);
656 sv1= screen_addvert(sc, sa->v1->vec.x, split);
657 sv2= screen_addvert(sc, sa->v4->vec.x, split);
660 screen_addedge(sc, sa->v1, sv1);
661 screen_addedge(sc, sv1, sa->v2);
662 screen_addedge(sc, sa->v3, sv2);
663 screen_addedge(sc, sv2, sa->v4);
664 screen_addedge(sc, sv1, sv2);
667 newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
668 area_copy_data(newa, sa, 0);
677 sv1= screen_addvert(sc, split, sa->v1->vec.y);
678 sv2= screen_addvert(sc, split, sa->v2->vec.y);
681 screen_addedge(sc, sa->v1, sv1);
682 screen_addedge(sc, sv1, sa->v4);
683 screen_addedge(sc, sa->v2, sv2);
684 screen_addedge(sc, sv2, sa->v3);
685 screen_addedge(sc, sv1, sv2);
687 /* new areas: left */
688 newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
689 area_copy_data(newa, sa, 0);
696 /* remove double vertices en edges */
697 removedouble_scrverts(sc);
698 removedouble_scredges(sc);
699 removenotused_scredges(sc);
705 /* Helper function to join 2 areas, it has a return value, 0=failed 1=success
706 * used by the split, join and rip operators
708 int screen_join_areas(bScreen* scr, ScrArea *sa1, ScrArea *sa2)
712 dir = area_getorientation(scr, sa1, sa2);
713 /*printf("dir is : %i \n", dir);*/
717 if (sa1 ) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
718 if (sa2 ) sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
725 screen_addedge(scr, sa1->v2, sa1->v3);
726 screen_addedge(scr, sa1->v1, sa1->v4);
731 screen_addedge(scr, sa1->v1, sa1->v2);
732 screen_addedge(scr, sa1->v3, sa1->v4);
737 screen_addedge(scr, sa1->v2, sa1->v3);
738 screen_addedge(scr, sa1->v1, sa1->v4);
743 screen_addedge(scr, sa1->v1, sa1->v2);
744 screen_addedge(scr, sa1->v3, sa1->v4);
747 screen_delarea(scr, sa2);
748 removedouble_scrverts(scr);
749 sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
754 /* *************************************************************** */
756 /* test if screen vertices should be scaled */
757 void screen_test_scale(bScreen *sc, int winsizex, int winsizey)
762 float facx, facy, tempf, min[2], max[2];
765 min[0]= min[1]= 10000.0f;
766 max[0]= max[1]= 0.0f;
768 for(sv= sc->vertbase.first; sv; sv= sv->next) {
769 min[0]= MIN2(min[0], sv->vec.x);
770 min[1]= MIN2(min[1], sv->vec.y);
771 max[0]= MAX2(max[0], sv->vec.x);
772 max[1]= MAX2(max[1], sv->vec.y);
775 /* always make 0.0 left under */
776 for(sv= sc->vertbase.first; sv; sv= sv->next) {
781 sizex= max[0]-min[0];
782 sizey= max[1]-min[1];
784 if(sizex!= winsizex || sizey!= winsizey) {
790 /* make sure it fits! */
791 for(sv= sc->vertbase.first; sv; sv= sv->next) {
792 tempf= ((float)sv->vec.x)*facx;
793 sv->vec.x= (short)(tempf+0.5);
794 sv->vec.x+= AREAGRID-1;
795 sv->vec.x-= (sv->vec.x % AREAGRID);
797 CLAMP(sv->vec.x, 0, winsizex);
799 tempf= ((float)sv->vec.y )*facy;
800 sv->vec.y= (short)(tempf+0.5);
801 sv->vec.y+= AREAGRID-1;
802 sv->vec.y-= (sv->vec.y % AREAGRID);
804 CLAMP(sv->vec.y, 0, winsizey);
808 /* test for collapsed areas. This could happen in some blender version... */
809 for(sa= sc->areabase.first; sa; sa= san) {
811 if(sa->v1==sa->v2 || sa->v3==sa->v4 || sa->v2==sa->v3)
812 screen_delarea(sc, sa);
818 #define SCR_BACK 0.55
821 /** join areas arrow drawing **/
822 typedef struct point{
826 /* draw vertical shape visualising future joining (left as well
827 * right direction of future joining) */
828 static void draw_horizontal_join_shape(ScrArea *sa, char dir)
833 float width = sa->v3->vec.x - sa->v1->vec.x;
834 float height = sa->v3->vec.y - sa->v1->vec.y;
845 points[0].x = sa->v1->vec.x;
846 points[0].y = sa->v1->vec.y + height/2;
848 points[1].x = sa->v1->vec.x;
849 points[1].y = sa->v1->vec.y;
851 points[2].x = sa->v4->vec.x - w;
852 points[2].y = sa->v4->vec.y;
854 points[3].x = sa->v4->vec.x - w;
855 points[3].y = sa->v4->vec.y + height/2 - 2*h;
857 points[4].x = sa->v4->vec.x - 2*w;
858 points[4].y = sa->v4->vec.y + height/2;
860 points[5].x = sa->v4->vec.x - w;
861 points[5].y = sa->v4->vec.y + height/2 + 2*h;
863 points[6].x = sa->v3->vec.x - w;
864 points[6].y = sa->v3->vec.y;
866 points[7].x = sa->v2->vec.x;
867 points[7].y = sa->v2->vec.y;
869 points[8].x = sa->v4->vec.x;
870 points[8].y = sa->v4->vec.y + height/2 - h;
872 points[9].x = sa->v4->vec.x;
873 points[9].y = sa->v4->vec.y + height/2 + h;
876 /* when direction is left, then we flip direction of arrow */
877 float cx = sa->v1->vec.x + width;
880 points[i].x = -points[i].x;
881 points[i].x += sa->v1->vec.x;
887 glVertex2f(points[i].x, points[i].y);
891 glVertex2f(points[i].x, points[i].y);
892 glVertex2f(points[0].x, points[0].y);
895 glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
896 glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
899 /* draw vertical shape visualising future joining (up/down direction) */
900 static void draw_vertical_join_shape(ScrArea *sa, char dir)
905 float width = sa->v3->vec.x - sa->v1->vec.x;
906 float height = sa->v3->vec.y - sa->v1->vec.y;
917 points[0].x = sa->v1->vec.x + width/2;
918 points[0].y = sa->v3->vec.y;
920 points[1].x = sa->v2->vec.x;
921 points[1].y = sa->v2->vec.y;
923 points[2].x = sa->v1->vec.x;
924 points[2].y = sa->v1->vec.y + h;
926 points[3].x = sa->v1->vec.x + width/2 - 2*w;
927 points[3].y = sa->v1->vec.y + h;
929 points[4].x = sa->v1->vec.x + width/2;
930 points[4].y = sa->v1->vec.y + 2*h;
932 points[5].x = sa->v1->vec.x + width/2 + 2*w;
933 points[5].y = sa->v1->vec.y + h;
935 points[6].x = sa->v4->vec.x;
936 points[6].y = sa->v4->vec.y + h;
938 points[7].x = sa->v3->vec.x;
939 points[7].y = sa->v3->vec.y;
941 points[8].x = sa->v1->vec.x + width/2 - w;
942 points[8].y = sa->v1->vec.y;
944 points[9].x = sa->v1->vec.x + width/2 + w;
945 points[9].y = sa->v1->vec.y;
948 /* when direction is up, then we flip direction of arrow */
949 float cy = sa->v1->vec.y + height;
952 points[i].y = -points[i].y;
953 points[i].y += sa->v1->vec.y;
959 glVertex2f(points[i].x, points[i].y);
963 glVertex2f(points[i].x, points[i].y);
964 glVertex2f(points[0].x, points[0].y);
967 glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
968 glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
971 /* draw join shape due to direction of joining */
972 static void draw_join_shape(ScrArea *sa, char dir)
974 if(dir=='u' || dir=='d')
975 draw_vertical_join_shape(sa, dir);
977 draw_horizontal_join_shape(sa, dir);
980 /* draw screen area darker with arrow (visualisation of future joining) */
981 static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
983 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
985 glColor4ub(0, 0, 0, 50);
986 draw_join_shape(sa, dir);
990 /* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
991 static void scrarea_draw_shape_light(ScrArea *sa, char dir)
993 glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
995 /* value 181 was hardly computed: 181~105 */
996 glColor4ub(255, 255, 255, 50);
997 /* draw_join_shape(sa, dir); */
998 glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
1002 /** screen edges drawing **/
1003 static void drawscredge_area(ScrArea *sa)
1006 short x1= sa->v1->vec.x;
1007 short xa1= x1+HEADERY;
1008 short y1= sa->v1->vec.y;
1009 short ya1= y1+HEADERY;
1010 short x2= sa->v3->vec.x;
1011 short xb2= x2-HEADERY;
1012 short y2= sa->v3->vec.y;
1013 short yb2= y2-HEADERY;
1017 /* right border area */
1018 sdrawline(x2, y1, x2, y2);
1020 /* left border area */
1021 if(x1>0) { /* otherwise it draws the emboss of window over */
1022 sdrawline(x1, y1, x1, y2);
1025 /* top border area */
1026 sdrawline(x1, y2, x2, y2);
1028 /* bottom border area */
1029 sdrawline(x1, y1, x2, y1);
1031 /* temporary viz for 'action corner' */
1032 for(az= sa->actionzones.first; az; az= az->next) {
1033 if(az->type==AZONE_TRI) sdrawtrifill(az->x1, az->y1, az->x2, az->y2, .2, .2, .2);
1034 //if(az->type==AZONE_TRI) sdrawtri(az->x1, az->y1, az->x2, az->y2);
1038 void ED_screen_do_listen(wmWindow *win, wmNotifier *note)
1042 switch(note->type) {
1043 case WM_NOTE_WINDOW_REDRAW:
1044 win->screen->do_draw= 1;
1046 case WM_NOTE_SCREEN_CHANGED:
1047 win->screen->do_draw= win->screen->do_refresh= 1;
1049 case WM_NOTE_AREA_SPLIT:
1050 printf("WM_NOTE_AREA_SPLIT\n");
1052 case WM_NOTE_AREA_DRAG:
1053 printf("WM_NOTE_AREA_DRAG\n");
1055 case WM_NOTE_GESTURE_CHANGED:
1056 printf("WM_NOTE_GESTURE_CHANGED\n");
1057 win->screen->do_gesture= 1;
1063 void ED_screen_draw(wmWindow *win)
1071 wm_subwindow_set(win, win->screen->mainwin);
1073 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1074 if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
1075 if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
1076 drawscredge_area(sa);
1080 dir = area_getorientation(win->screen, sa1, sa2);
1101 scrarea_draw_shape_dark(sa2, dir);
1102 scrarea_draw_shape_light(sa1, dira);
1104 if(G.f & G_DEBUG) printf("draw screen\n");
1105 win->screen->do_draw= 0;
1108 void ED_screen_gesture(wmWindow *win)
1110 if(G.f & G_DEBUG) printf("gesture draw screen\n");
1112 if(win->gesture.first) {
1113 ed_gesture_update(win);
1115 win->screen->do_gesture= 0;
1118 /* make this screen usable */
1119 /* for file read and first use, for scaling window, area moves */
1120 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
1124 rcti winrct= {0, win->sizex, 0, win->sizey};
1126 screen_test_scale(win->screen, win->sizex, win->sizey);
1128 if(win->screen->mainwin==0)
1129 win->screen->mainwin= wm_subwindow_open(win, &winrct);
1131 wm_subwindow_position(win, win->screen->mainwin, &winrct);
1133 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1134 /* set spacetype and region callbacks */
1135 /* sets subwindow */
1136 ED_area_initialize(wm, win, sa);
1139 for(ar= win->screen->regionbase.first; ar; ar= ar->next) {
1141 ED_region_initialize(wm, win, ar);
1144 if(G.f & G_DEBUG) printf("set screen\n");
1145 win->screen->do_refresh= 0;
1149 /* file read, set all screens, ... */
1150 void ED_screens_initialize(wmWindowManager *wm)
1154 for(win= wm->windows.first; win; win= win->next) {
1156 if(win->screen==NULL)
1157 win->screen= G.main->screen.first;
1159 ED_screen_refresh(wm, win);
1163 void ED_region_exit(bContext *C, ARegion *ar)
1165 WM_operator_cancel(C, &ar->modalops, NULL);
1166 WM_event_remove_handlers(&ar->handlers);
1169 void ED_area_exit(bContext *C, ScrArea *sa)
1173 for(ar= sa->regionbase.first; ar; ar= ar->next)
1174 ED_region_exit(C, ar);
1176 WM_operator_cancel(C, &sa->modalops, NULL);
1177 WM_event_remove_handlers(&sa->handlers);
1180 void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
1185 for(ar= screen->regionbase.first; ar; ar= ar->next)
1186 ED_region_exit(C, ar);
1188 for(sa= screen->areabase.first; sa; sa= sa->next)
1189 ED_area_exit(C, sa);
1191 WM_operator_cancel(C, &window->modalops, NULL);
1192 WM_event_remove_handlers(&window->handlers);
1197 removenotused_scrverts(NULL);
1198 removenotused_scredges(NULL);
1201 /* called in wm_event_system.c. sets state var in screen */
1202 void ED_screen_set_subwinactive(wmWindow *win)
1205 wmEvent *event= win->eventstate;
1208 for(sa= win->screen->areabase.first; sa; sa= sa->next) {
1209 if(event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
1210 if(event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
1215 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1216 if(BLI_in_rcti(&ar->winrct, event->x, event->y))
1217 win->screen->subwinactive= ar->swinid;
1221 win->screen->subwinactive= win->screen->mainwin;
1226 /* ****************** cursor near edge operator ********************************* */
1229 int screen_cursor_test(bContext *C, wmOperator *op, wmEvent *event)
1231 if (C->screen->subwinactive==C->screen->mainwin) {
1232 ScrEdge *actedge= screen_find_active_scredge(C->screen, event->x, event->y);
1234 if (actedge && scredge_is_horizontal(actedge)) {
1235 WM_set_cursor(C, CURSOR_Y_MOVE);
1237 WM_set_cursor(C, CURSOR_X_MOVE);
1242 for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1243 az= is_in_area_actionzone(sa, event->x, event->y);
1246 if(az!=NULL) WM_set_cursor(C, CURSOR_EDIT);
1247 else WM_set_cursor(C, CURSOR_STD);
1250 return OPERATOR_PASS_THROUGH;
1253 /* ************** move area edge operator *********************************** */
1255 /* operator state vars used:
1256 x, y mouse coord near edge
1257 delta movement of edge
1261 init() set default property values, find edge based on mouse coords, test
1262 if the edge can be moved, select edges, calculate min and max movement
1264 apply() apply delta on selection
1266 exit() cleanup, send notifier
1270 exec() execute without any user interaction, based on properties
1271 call init(), apply(), exit()
1273 invoke() gets called on mouse click near edge
1274 call init(), add handler
1276 modal() accept modal events while doing it
1277 call apply() with delta motion
1278 call exit() and remove handler
1280 cancel() cancel moving
1284 typedef struct sAreaMoveData {
1285 int bigger, smaller, origval;
1289 /* validate selection inside screen, set variables OK */
1290 /* return 0: init failed */
1291 static int move_areas_init (bContext *C, wmOperator *op)
1298 /* required properties */
1299 if(!(OP_get_int(op, "x", &x) && OP_get_int(op, "y", &y)))
1302 /* default properties */
1303 OP_verify_int(op, "delta", 0, NULL);
1306 actedge= screen_find_active_scredge(C->screen, x, y);
1307 if(actedge==NULL) return 0;
1309 md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
1312 md->dir= scredge_is_horizontal(actedge)?'h':'v';
1313 if(md->dir=='h') md->origval= actedge->v1->vec.y;
1314 else md->origval= actedge->v1->vec.x;
1316 select_connected_scredge(C->screen, actedge);
1318 /* now all verices with 'flag==1' are the ones that can be moved. */
1319 /* we check all areas and test for free space with MINSIZE */
1320 md->bigger= md->smaller= 10000;
1321 for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1322 if(md->dir=='h') { /* if top or down edge selected, test height */
1324 if(sa->v1->flag && sa->v4->flag) {
1325 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
1326 md->bigger= MIN2(md->bigger, y1);
1328 else if(sa->v2->flag && sa->v3->flag) {
1329 int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
1330 md->smaller= MIN2(md->smaller, y1);
1333 else { /* if left or right edge selected, test width */
1334 if(sa->v1->flag && sa->v2->flag) {
1335 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
1336 md->bigger= MIN2(md->bigger, x1);
1338 else if(sa->v3->flag && sa->v4->flag) {
1339 int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
1340 md->smaller= MIN2(md->smaller, x1);
1348 /* moves selected screen edge amount of delta */
1349 /* needs init call to work */
1350 static void move_areas_apply(bContext *C, wmOperator *op)
1354 sAreaMoveData *md= op->customdata;
1356 OP_get_int(op, "delta", &delta);
1358 delta= CLAMPIS(delta, -md->smaller, md->bigger);
1360 for (v1= C->screen->vertbase.first; v1; v1= v1->next) {
1362 /* that way a nice AREAGRID */
1363 if((md->dir=='v') && v1->vec.x>0 && v1->vec.x<C->window->sizex-1) {
1364 v1->vec.x= md->origval + delta;
1365 if(delta != md->bigger && delta != -md->smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
1367 if((md->dir=='h') && v1->vec.y>0 && v1->vec.y<C->window->sizey-1) {
1368 v1->vec.y= md->origval + delta;
1370 v1->vec.y+= AREAGRID-1;
1371 v1->vec.y-= (v1->vec.y % AREAGRID);
1373 /* prevent too small top header */
1374 if(v1->vec.y > C->window->sizey-HEADERY)
1375 v1->vec.y= C->window->sizey-HEADERY;
1380 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1383 static void move_areas_exit(bContext *C, wmOperator *op)
1386 MEM_freeN(op->customdata);
1388 /* this makes sure aligned edges will result in aligned grabbing */
1389 removedouble_scrverts(C->screen);
1390 removedouble_scredges(C->screen);
1393 static int move_areas_exec(bContext *C, wmOperator *op)
1395 if(!move_areas_init(C, op))
1396 return OPERATOR_CANCELLED;
1398 move_areas_apply(C, op);
1399 move_areas_exit(C, op);
1401 return OPERATOR_FINISHED;
1404 /* interaction callback */
1405 static int move_areas_invoke(bContext *C, wmOperator *op, wmEvent *event)
1407 OP_verify_int(op, "x", event->x, NULL);
1408 OP_verify_int(op, "y", event->y, NULL);
1410 if(!move_areas_init(C, op))
1411 return OPERATOR_PASS_THROUGH;
1413 /* add temp handler */
1414 WM_event_add_modal_handler(&C->window->handlers, op);
1416 return OPERATOR_RUNNING_MODAL;
1419 static int move_areas_cancel(bContext *C, wmOperator *op)
1421 WM_event_remove_modal_handler(&C->window->handlers, op);
1423 OP_set_int(op, "delta", 0);
1424 move_areas_apply(C, op);
1425 move_areas_exit(C, op);
1427 return OPERATOR_CANCELLED;
1430 /* modal callback for while moving edges */
1431 static int move_areas_modal(bContext *C, wmOperator *op, wmEvent *event)
1438 OP_get_int(op, "x", &x);
1439 OP_get_int(op, "y", &y);
1441 /* execute the events */
1442 switch(event->type) {
1444 delta= (md->dir == 'v')? event->x - x: event->y - y;
1445 OP_set_int(op, "delta", delta);
1447 move_areas_apply(C, op);
1452 move_areas_exit(C, op);
1453 WM_event_remove_modal_handler(&C->window->handlers, op);
1454 return OPERATOR_FINISHED;
1459 return move_areas_cancel(C, op);
1462 return OPERATOR_RUNNING_MODAL;
1465 void ED_SCR_OT_move_areas(wmOperatorType *ot)
1468 ot->name= "Move area edges";
1469 ot->idname= "ED_SCR_OT_move_areas";
1471 ot->exec= move_areas_exec;
1472 ot->invoke= move_areas_invoke;
1473 ot->cancel= move_areas_cancel;
1474 ot->modal= move_areas_modal;
1476 ot->poll= ED_operator_screen_mainwinactive;
1479 /****************** split area ********************/
1480 /* we do split on init, then we work like move_areas
1481 if operation gets cancelled -> join
1482 if operation gets confirmed -> yay
1485 #define SPLIT_STARTED 1
1486 #define SPLIT_PROGRESS 2
1487 #define SPLIT_DONE 3
1489 typedef struct sAreaSplitData
1491 int state; /* state of operation */
1492 int dir; /* direction of new edge */
1494 int origval; /* for move areas */
1495 int min,max; /* constraints for moving new edge */
1496 int pos; /* with sa as center, ne is located at: 0=W, 1=N, 2=E, 3=S */
1497 ScrEdge *nedge; /* new edge */
1498 ScrEdge *aedge; /* active edge */
1499 ScrArea *sarea; /* start area */
1500 ScrArea *narea; /* new area */
1503 static int split_area_init(bContext *C, wmOperator *op)
1507 sAreaSplitData *sd= NULL;
1510 /* required properties */
1511 if(!(OP_get_int(op, "x", &x) && OP_get_int(op, "y", &y)))
1514 OP_verify_int(op, "delta", 0, NULL);
1515 OP_verify_int(op, "dir", 0, NULL);
1517 for(sa= C->screen->areabase.first; sa; sa= sa->next) {
1518 az= is_in_area_actionzone(sa, x, y);
1522 if(az==NULL) return 0;
1524 sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_split_area");
1527 sd->state= SPLIT_STARTED;
1534 /* the moving of the new egde */
1535 static void split_area_apply(bContext *C, wmOperator *op)
1537 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1538 int newval, delta, dir;
1540 OP_get_int(op, "delta", &delta);
1541 OP_get_int(op, "dir", &dir);
1543 newval= sd->origval + delta;
1544 newval= CLAMPIS(newval, -sd->min, sd->max);
1546 if((dir=='v') && (newval > sd->min && newval < sd->max-1)) {
1547 sd->nedge->v1->vec.x= newval;
1548 sd->nedge->v2->vec.x= newval;
1550 if((dir=='h') && (newval > sd->min+HEADERY && newval < sd->max-HEADERY)) {
1551 sd->nedge->v1->vec.y= newval;
1552 sd->nedge->v2->vec.y= newval;
1556 static void split_area_exit(bContext *C, wmOperator *op)
1558 if (op->customdata) {
1559 MEM_freeN(op->customdata);
1560 op->customdata = NULL;
1563 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1565 /* this makes sure aligned edges will result in aligned grabbing */
1566 removedouble_scrverts(C->screen);
1567 removedouble_scredges(C->screen);
1570 static int split_area_init_intern(bContext *C, wmOperator *op, sAreaSplitData *sd)
1575 OP_get_int(op, "dir", &dir);
1578 OP_get_int(op, "y", &sd->origval);
1579 fac= 1.0 - ((float)(sd->sarea->v3->vec.y - sd->origval)) / (float)sd->sarea->winy;
1580 sd->min= sd->aedge->v1->vec.y;
1581 sd->max= sd->aedge->v2->vec.y;
1584 OP_get_int(op, "x", &sd->origval);
1585 fac= 1.0 - ((float)(sd->sarea->v4->vec.x - sd->origval)) / (float)sd->sarea->winx;
1586 sd->min= sd->aedge->v1->vec.x;
1587 sd->max= sd->aedge->v2->vec.x;
1590 sd->narea= splitarea(C->window, C->screen, sd->sarea, dir, fac);
1592 if(sd->narea==NULL) return 0;
1594 sd->nedge= area_findsharededge(C->screen, sd->sarea, sd->narea);
1596 /* select newly created edge */
1597 select_connected_scredge(C->screen, sd->nedge);
1599 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1604 static int split_area_exec(bContext *C, wmOperator *op)
1606 /* XXX: this does nothing, part of the code should be moved
1609 if(!split_area_init(C, op))
1610 return OPERATOR_CANCELLED;
1612 split_area_apply(C, op);
1613 split_area_exit(C, op);
1615 return OPERATOR_FINISHED;
1618 static int split_area_invoke(bContext *C, wmOperator *op, wmEvent *event)
1620 OP_verify_int(op, "x", event->x, NULL);
1621 OP_verify_int(op, "y", event->y, NULL);
1623 if(!split_area_init(C, op))
1624 return OPERATOR_PASS_THROUGH;
1626 /* add temp handler */
1627 WM_event_add_modal_handler(&C->window->handlers, op);
1629 return OPERATOR_RUNNING_MODAL;
1632 static int split_area_cancel(bContext *C, wmOperator *op)
1634 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1636 WM_event_remove_modal_handler(&C->window->handlers, op);
1638 OP_set_int(op, "delta", 0);
1639 if (screen_join_areas(C->screen,sd->sarea, sd->narea)) {
1640 if (C->area == sd->narea) {
1645 split_area_exit(C, op);
1647 return OPERATOR_CANCELLED;
1650 static int split_area_modal(bContext *C, wmOperator *op, wmEvent *event)
1652 ScrArea *sa= NULL, *sold=NULL;
1653 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1656 OP_get_int(op, "x", &x);
1657 OP_get_int(op, "y", &y);
1658 OP_get_int(op, "dir", &dir);
1660 /* execute the events */
1661 switch(event->type) {
1663 if(sd->state==SPLIT_STARTED) {
1665 We first want to determine direction for split.
1666 Get at least one(x or y) delta of minimum 10 pixels.
1667 If one dir is delta threshold, and other dir is within "grey area" -> vert/hor split.
1668 If we get both over threshold -> subdiv.
1670 sd->deltax= event->x - x;
1671 sd->deltay= event->y - y;
1673 if(sd->deltax>10 && sd->deltay<4) {
1674 printf("split on v\n");
1675 sd->state= SPLIT_PROGRESS;
1676 OP_set_int(op, "dir", 'v');
1677 OP_set_int(op, "delta", sd->deltax);
1678 } else if(sd->deltay>10 && sd->deltax<4) {
1679 printf("split on h\n");
1680 sd->state= SPLIT_PROGRESS;
1681 OP_set_int(op, "dir", 'h');
1682 OP_set_int(op, "delta", sd->deltay);
1685 } else if(sd->state==SPLIT_PROGRESS) {
1686 sa= screen_areahascursor(C->screen, event->x, event->y);
1688 /* area containing cursor has changed */
1689 if(sa && sd->sarea!=sa && sd->narea!=sa) {
1691 if (screen_join_areas(C->screen,sd->sarea, sd->narea)) {
1692 if (C->area == sd->narea) {
1698 /* now find aedge with same orientation as sd->dir (inverted) */
1700 sd->aedge= screen_findedge(C->screen, sa->v1, sa->v4);
1701 if(sd->aedge==NULL) sd->aedge= screen_findedge(C->screen, sa->v2, sa->v3);
1704 sd->aedge= screen_findedge(C->screen, sa->v1, sa->v2);
1705 if(sd->aedge==NULL) sd->aedge= screen_findedge(C->screen, sa->v3, sa->v4);
1708 /* set sd and op to new init state */
1710 OP_set_int(op, "delta", 0);
1711 OP_set_int(op, "x", event->x);
1712 OP_set_int(op, "y", event->y);
1713 split_area_init_intern(C, op, sd);
1716 /* all is cool, update delta according complicated formula */
1718 OP_set_int(op, "delta", event->x - y);
1720 OP_set_int(op, "delta", event->x - y);
1722 split_area_apply(C, op);
1724 } else if (sd->state==SPLIT_DONE) {
1725 /* shouldn't get here anymore */
1727 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1730 if(event->val==0) { /* mouse up => confirm if not near/on starting edge */
1731 split_area_exit(C, op);
1732 WM_event_remove_modal_handler(&C->window->handlers, op);
1733 return OPERATOR_FINISHED;
1736 case RIGHTMOUSE: /* cancel operation */
1738 return split_area_cancel(C, op);
1741 return OPERATOR_RUNNING_MODAL;
1744 void ED_SCR_OT_split_area(wmOperatorType *ot)
1746 ot->name = "Split area";
1747 ot->idname = "ED_SCR_OT_split_area";
1749 ot->exec= split_area_exec;
1750 ot->invoke= split_area_invoke;
1751 ot->modal= split_area_modal;
1753 ot->poll= ED_operator_screenactive;
1756 /* ************** join area operator ********************************************** */
1758 /* operator state vars used:
1759 x, y mouse coord near edge
1760 delta movement of edge
1764 init() find edge based on op->veci,
1765 test if the edge divides two areas,
1766 store active and nonactive area,
1770 exit() cleanup, send notifier
1772 exec() remove active window,
1774 make nonactive window active,
1775 add notifier for redraw.
1777 invoke() handler gets called on Alt+RMB near edge
1781 modal() accept modal events while doing it
1782 call apply() with active window and nonactive window
1783 call exit() and remove handler when LMB confirm
1787 typedef struct sAreaJoinData
1790 ScrArea *sa1; /* first area to be considered */
1791 ScrArea *sa2; /* second area to be considered */
1792 ScrArea *scr; /* designed for removal */
1797 /* validate selection inside screen, set variables OK */
1798 /* return 0: init failed */
1799 static int join_areas_init(bContext *C, wmOperator *op)
1801 ScrArea *actarea = NULL;
1802 sAreaJoinData* jd= NULL;
1805 if(!(OP_get_int(op, "x", &x) && OP_get_int(op, "y", &y)))
1808 actarea = screen_areahascursor(C->screen, x, y);
1812 jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_join_areas");
1815 jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1822 /* apply the join of the areas (space types) */
1823 static int join_areas_apply(bContext *C, wmOperator *op)
1825 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1828 if(!screen_join_areas(C->screen,jd->sa1,jd->sa2)){
1831 if (C->area == jd->sa2) {
1838 static int is_inside_area(ScrArea *ar, short x, short y)
1841 if ( (ar->v1->vec.x < x) && (x < ar->v3->vec.x) ) {
1842 if ( (y<ar->v3->vec.y) && (ar->v1->vec.y<y) ) {
1850 /* finish operation */
1851 static void join_areas_exit(bContext *C, wmOperator *op)
1853 if (op->customdata) {
1854 MEM_freeN(op->customdata);
1855 op->customdata = NULL;
1858 /* this makes sure aligned edges will result in aligned grabbing */
1859 removedouble_scredges(C->screen);
1860 removenotused_scredges(C->screen);
1861 removenotused_scrverts(C->screen);
1864 static int join_areas_exec(bContext *C, wmOperator *op)
1866 if(!join_areas_init(C, op))
1867 return OPERATOR_CANCELLED;
1869 join_areas_apply(C, op);
1870 join_areas_exit(C, op);
1872 return OPERATOR_FINISHED;
1875 /* interaction callback */
1876 static int join_areas_invoke(bContext *C, wmOperator *op, wmEvent *event)
1878 OP_verify_int(op, "x", event->x, NULL);
1879 OP_verify_int(op, "y", event->y, NULL);
1881 if(!join_areas_init(C, op))
1882 return OPERATOR_PASS_THROUGH;
1884 /* add temp handler */
1885 WM_event_add_modal_handler(&C->window->handlers, op);
1887 return OPERATOR_RUNNING_MODAL;
1890 static int join_areas_cancel(bContext *C, wmOperator *op)
1892 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1895 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1896 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1899 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1900 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1903 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1904 WM_event_remove_modal_handler(&C->window->handlers, op);
1905 OP_set_int(op, "delta", 0);
1906 join_areas_exit(C, op);
1908 return OPERATOR_CANCELLED;
1911 /* modal callback while selecting area (space) that will be removed */
1912 static int join_areas_modal(bContext *C, wmOperator *op, wmEvent *event)
1914 /* execute the events */
1915 switch(event->type) {
1919 sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1920 ScrArea *sa = screen_areahascursor(C->screen, event->x, event->y);
1922 if (jd->sa1 != sa) {
1923 jd->dir = area_getorientation(C->screen, jd->sa1, sa);
1926 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1928 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1930 /* we are not bordering on the previously selected area
1931 we check if area has common border with the one marked for removal
1932 in this case we can swap areas.
1934 jd->dir = area_getorientation(C->screen, sa, jd->sa2);
1936 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1937 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1940 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1941 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1943 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1947 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1949 /* we are back in the area previously selected for keeping
1950 * we swap the areas if possible to allow user to choose */
1951 if (jd->sa2 != NULL) {
1952 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1953 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1956 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1957 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1958 jd->dir = area_getorientation(C->screen, jd->sa1, jd->sa2);
1961 printf("oops, didn't expect that!\n");
1964 jd->dir = area_getorientation(C->screen, jd->sa1, sa);
1967 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1969 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1972 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1980 join_areas_apply(C, op);
1981 WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1982 join_areas_exit(C, op);
1983 WM_event_remove_modal_handler(&C->window->handlers, op);
1984 return OPERATOR_FINISHED;
1989 return join_areas_cancel(C, op);
1992 return OPERATOR_RUNNING_MODAL;
1995 /* Operator for joining two areas (space types) */
1996 void ED_SCR_OT_join_areas(wmOperatorType *ot)
1999 ot->name= "Join area";
2000 ot->idname= "ED_SCR_OT_join_areas";
2003 ot->exec= join_areas_exec;
2004 ot->invoke= join_areas_invoke;
2005 ot->cancel= join_areas_cancel;
2006 ot->modal= join_areas_modal;
2008 ot->poll= ED_operator_screenactive;