d59109a5baa2369fe852a4f2386c61b41a7e9be1
[blender.git] / source / blender / editors / screen / screen_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/screen/screen_edit.c
26  *  \ingroup edscr
27  */
28
29
30 #include <string.h>
31 #include <math.h>
32
33
34 #include "MEM_guardedalloc.h"
35
36 #include "DNA_scene_types.h"
37 #include "DNA_userdef_types.h"
38
39 #include "BLI_math.h"
40 #include "BLI_blenlib.h"
41 #include "BLI_utildefines.h"
42
43 #include "BKE_context.h"
44 #include "BKE_depsgraph.h"
45 #include "BKE_icons.h"
46 #include "BKE_image.h"
47 #include "BKE_global.h"
48 #include "BKE_library.h"
49 #include "BKE_library_remap.h"
50 #include "BKE_main.h"
51 #include "BKE_node.h"
52 #include "BKE_screen.h"
53 #include "BKE_scene.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58 #include "ED_object.h"
59 #include "ED_screen.h"
60 #include "ED_screen_types.h"
61 #include "ED_clip.h"
62 #include "ED_node.h"
63 #include "ED_render.h"
64
65 #include "UI_interface.h"
66
67 /* XXX actually should be not here... solve later */
68 #include "wm_subwindow.h"
69
70 #include "screen_intern.h"  /* own module include */
71
72
73 /* ******************* screen vert, edge, area managing *********************** */
74
75 static ScrVert *screen_addvert(bScreen *sc, short x, short y)
76 {
77         ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert");
78         sv->vec.x = x;
79         sv->vec.y = y;
80         
81         BLI_addtail(&sc->vertbase, sv);
82         return sv;
83 }
84
85 static void sortscrvert(ScrVert **v1, ScrVert **v2)
86 {
87         ScrVert *tmp;
88         
89         if (*v1 > *v2) {
90                 tmp = *v1;
91                 *v1 = *v2;
92                 *v2 = tmp;
93         }
94 }
95
96 static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
97 {
98         ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge");
99         
100         sortscrvert(&v1, &v2);
101         se->v1 = v1;
102         se->v2 = v2;
103         
104         BLI_addtail(&sc->edgebase, se);
105         return se;
106 }
107
108
109 ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
110 {
111         ScrEdge *se;
112         
113         sortscrvert(&v1, &v2);
114         for (se = sc->edgebase.first; se; se = se->next)
115                 if (se->v1 == v1 && se->v2 == v2)
116                         return se;
117         
118         return NULL;
119 }
120
121 void removedouble_scrverts(bScreen *sc)
122 {
123         ScrVert *v1, *verg;
124         ScrEdge *se;
125         ScrArea *sa;
126         
127         verg = sc->vertbase.first;
128         while (verg) {
129                 if (verg->newv == NULL) { /* !!! */
130                         v1 = verg->next;
131                         while (v1) {
132                                 if (v1->newv == NULL) {   /* !?! */
133                                         if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
134                                                 /* printf("doublevert\n"); */
135                                                 v1->newv = verg;
136                                         }
137                                 }
138                                 v1 = v1->next;
139                         }
140                 }
141                 verg = verg->next;
142         }
143
144         /* replace pointers in edges and faces */
145         se = sc->edgebase.first;
146         while (se) {
147                 if (se->v1->newv) se->v1 = se->v1->newv;
148                 if (se->v2->newv) se->v2 = se->v2->newv;
149                 /* edges changed: so.... */
150                 sortscrvert(&(se->v1), &(se->v2));
151                 se = se->next;
152         }
153         sa = sc->areabase.first;
154         while (sa) {
155                 if (sa->v1->newv) sa->v1 = sa->v1->newv;
156                 if (sa->v2->newv) sa->v2 = sa->v2->newv;
157                 if (sa->v3->newv) sa->v3 = sa->v3->newv;
158                 if (sa->v4->newv) sa->v4 = sa->v4->newv;
159                 sa = sa->next;
160         }
161
162         /* remove */
163         verg = sc->vertbase.first;
164         while (verg) {
165                 v1 = verg->next;
166                 if (verg->newv) {
167                         BLI_remlink(&sc->vertbase, verg);
168                         MEM_freeN(verg);
169                 }
170                 verg = v1;
171         }
172
173 }
174
175 void removenotused_scrverts(bScreen *sc)
176 {
177         ScrVert *sv, *svn;
178         ScrEdge *se;
179         
180         /* we assume edges are ok */
181         
182         se = sc->edgebase.first;
183         while (se) {
184                 se->v1->flag = 1;
185                 se->v2->flag = 1;
186                 se = se->next;
187         }
188         
189         sv = sc->vertbase.first;
190         while (sv) {
191                 svn = sv->next;
192                 if (sv->flag == 0) {
193                         BLI_remlink(&sc->vertbase, sv);
194                         MEM_freeN(sv);
195                 }
196                 else {
197                         sv->flag = 0;
198                 }
199                 sv = svn;
200         }
201 }
202
203 void removedouble_scredges(bScreen *sc)
204 {
205         ScrEdge *verg, *se, *sn;
206         
207         /* compare */
208         verg = sc->edgebase.first;
209         while (verg) {
210                 se = verg->next;
211                 while (se) {
212                         sn = se->next;
213                         if (verg->v1 == se->v1 && verg->v2 == se->v2) {
214                                 BLI_remlink(&sc->edgebase, se);
215                                 MEM_freeN(se);
216                         }
217                         se = sn;
218                 }
219                 verg = verg->next;
220         }
221 }
222
223 void removenotused_scredges(bScreen *sc)
224 {
225         ScrEdge *se, *sen;
226         ScrArea *sa;
227         int a = 0;
228         
229         /* sets flags when edge is used in area */
230         sa = sc->areabase.first;
231         while (sa) {
232                 se = screen_findedge(sc, sa->v1, sa->v2);
233                 if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
234                 else se->flag = 1;
235                 se = screen_findedge(sc, sa->v2, sa->v3);
236                 if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
237                 else se->flag = 1;
238                 se = screen_findedge(sc, sa->v3, sa->v4);
239                 if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
240                 else se->flag = 1;
241                 se = screen_findedge(sc, sa->v4, sa->v1);
242                 if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
243                 else se->flag = 1;
244                 sa = sa->next;
245                 a++;
246         }
247         se = sc->edgebase.first;
248         while (se) {
249                 sen = se->next;
250                 if (se->flag == 0) {
251                         BLI_remlink(&sc->edgebase, se);
252                         MEM_freeN(se);
253                 }
254                 else {
255                         se->flag = 0;
256                 }
257                 se = sen;
258         }
259 }
260
261 bool scredge_is_horizontal(ScrEdge *se)
262 {
263         return (se->v1->vec.y == se->v2->vec.y);
264 }
265
266 /* need win size to make sure not to include edges along screen edge */
267 ScrEdge *screen_find_active_scredge(bScreen *sc,
268                                     const int winsize_x, const int winsize_y,
269                                     const int mx, const int my)
270 {
271         ScrEdge *se;
272         int safety = U.widget_unit / 10;
273         
274         if (safety < 2) safety = 2;
275         
276         for (se = sc->edgebase.first; se; se = se->next) {
277                 if (scredge_is_horizontal(se)) {
278                         if (se->v1->vec.y > 0 && se->v1->vec.y < winsize_y - 1) {
279                                 short min, max;
280                                 min = MIN2(se->v1->vec.x, se->v2->vec.x);
281                                 max = MAX2(se->v1->vec.x, se->v2->vec.x);
282                                 
283                                 if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max)
284                                         return se;
285                         }
286                 }
287                 else {
288                         if (se->v1->vec.x > 0 && se->v1->vec.x < winsize_x - 1) {
289                                 short min, max;
290                                 min = MIN2(se->v1->vec.y, se->v2->vec.y);
291                                 max = MAX2(se->v1->vec.y, se->v2->vec.y);
292                                 
293                                 if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max)
294                                         return se;
295                         }
296                 }
297         }
298         
299         return NULL;
300 }
301
302
303
304 /* adds no space data */
305 static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
306 {
307         ScrArea *sa = MEM_callocN(sizeof(ScrArea), "addscrarea");
308         sa->v1 = v1;
309         sa->v2 = v2;
310         sa->v3 = v3;
311         sa->v4 = v4;
312         sa->headertype = headertype;
313         sa->spacetype = sa->butspacetype = spacetype;
314         
315         BLI_addtail(&sc->areabase, sa);
316         
317         return sa;
318 }
319
320 static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
321 {
322         
323         ED_area_exit(C, sa);
324         
325         BKE_screen_area_free(sa);
326         
327         BLI_remlink(&sc->areabase, sa);
328         MEM_freeN(sa);
329 }
330
331 /* return 0: no split possible */
332 /* else return (integer) screencoordinate split point */
333 static short testsplitpoint(ScrArea *sa, char dir, float fac)
334 {
335         short x, y;
336         const short area_min_x = AREAMINX;
337         const short area_min_y = ED_area_headersize();
338         
339         // area big enough?
340         if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * area_min_x)) return 0;
341         if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * area_min_y)) return 0;
342         
343         // to be sure
344         CLAMP(fac, 0.0f, 1.0f);
345         
346         if (dir == 'h') {
347                 y = sa->v1->vec.y + fac * (sa->v2->vec.y - sa->v1->vec.y);
348                 
349                 if (y - sa->v1->vec.y < area_min_y)
350                         y = sa->v1->vec.y + area_min_y;
351                 else if (sa->v2->vec.y - y < area_min_y)
352                         y = sa->v2->vec.y - area_min_y;
353                 else y -= (y % AREAGRID);
354                 
355                 return y;
356         }
357         else {
358                 x = sa->v1->vec.x + fac * (sa->v4->vec.x - sa->v1->vec.x);
359                 
360                 if (x - sa->v1->vec.x < area_min_x)
361                         x = sa->v1->vec.x + area_min_x;
362                 else if (sa->v4->vec.x - x < area_min_x)
363                         x = sa->v4->vec.x - area_min_x;
364                 else x -= (x % AREAGRID);
365                 
366                 return x;
367         }
368 }
369
370 ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
371 {
372         ScrArea *newa = NULL;
373         ScrVert *sv1, *sv2;
374         short split;
375         
376         if (sa == NULL) return NULL;
377         
378         split = testsplitpoint(sa, dir, fac);
379         if (split == 0) return NULL;
380         
381         /* note regarding (fac > 0.5f) checks below.
382          * normally it shouldn't matter which is used since the copy should match the original
383          * however with viewport rendering and python console this isn't the case. - campbell */
384
385         if (dir == 'h') {
386                 /* new vertices */
387                 sv1 = screen_addvert(sc, sa->v1->vec.x, split);
388                 sv2 = screen_addvert(sc, sa->v4->vec.x, split);
389                 
390                 /* new edges */
391                 screen_addedge(sc, sa->v1, sv1);
392                 screen_addedge(sc, sv1, sa->v2);
393                 screen_addedge(sc, sa->v3, sv2);
394                 screen_addedge(sc, sv2, sa->v4);
395                 screen_addedge(sc, sv1, sv2);
396                 
397                 if (fac > 0.5f) {
398                         /* new areas: top */
399                         newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
400
401                         /* area below */
402                         sa->v2 = sv1;
403                         sa->v3 = sv2;
404                 }
405                 else {
406                         /* new areas: bottom */
407                         newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->headertype, sa->spacetype);
408
409                         /* area above */
410                         sa->v1 = sv1;
411                         sa->v4 = sv2;
412                 }
413
414                 ED_area_data_copy(newa, sa, true);
415                 
416         }
417         else {
418                 /* new vertices */
419                 sv1 = screen_addvert(sc, split, sa->v1->vec.y);
420                 sv2 = screen_addvert(sc, split, sa->v2->vec.y);
421                 
422                 /* new edges */
423                 screen_addedge(sc, sa->v1, sv1);
424                 screen_addedge(sc, sv1, sa->v4);
425                 screen_addedge(sc, sa->v2, sv2);
426                 screen_addedge(sc, sv2, sa->v3);
427                 screen_addedge(sc, sv1, sv2);
428                 
429                 if (fac > 0.5f) {
430                         /* new areas: right */
431                         newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->headertype, sa->spacetype);
432
433                         /* area left */
434                         sa->v3 = sv2;
435                         sa->v4 = sv1;
436                 }
437                 else {
438                         /* new areas: left */
439                         newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
440
441                         /* area right */
442                         sa->v1 = sv1;
443                         sa->v2 = sv2;
444                 }
445
446                 ED_area_data_copy(newa, sa, true);
447         }
448         
449         /* remove double vertices en edges */
450         if (merge)
451                 removedouble_scrverts(sc);
452         removedouble_scredges(sc);
453         removenotused_scredges(sc);
454         
455         return newa;
456 }
457
458 /* empty screen, with 1 dummy area without spacedata */
459 /* uses window size */
460 bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name)
461 {
462         const int winsize_x = WM_window_pixels_x(win);
463         const int winsize_y = WM_window_pixels_y(win);
464
465         bScreen *sc;
466         ScrVert *sv1, *sv2, *sv3, *sv4;
467         
468         sc = BKE_libblock_alloc(G.main, ID_SCR, name);
469         sc->scene = scene;
470         sc->do_refresh = true;
471         sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
472         sc->winid = win->winid;
473
474         sv1 = screen_addvert(sc, 0, 0);
475         sv2 = screen_addvert(sc, 0, winsize_y - 1);
476         sv3 = screen_addvert(sc, winsize_x - 1, winsize_y - 1);
477         sv4 = screen_addvert(sc, winsize_x - 1, 0);
478         
479         screen_addedge(sc, sv1, sv2);
480         screen_addedge(sc, sv2, sv3);
481         screen_addedge(sc, sv3, sv4);
482         screen_addedge(sc, sv4, sv1);
483         
484         /* dummy type, no spacedata */
485         screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY);
486                 
487         return sc;
488 }
489
490 static void screen_copy(bScreen *to, bScreen *from)
491 {
492         ScrVert *s1, *s2;
493         ScrEdge *se;
494         ScrArea *sa, *saf;
495         
496         /* free contents of 'to', is from blenkernel screen.c */
497         BKE_screen_free(to);
498         
499         BLI_duplicatelist(&to->vertbase, &from->vertbase);
500         BLI_duplicatelist(&to->edgebase, &from->edgebase);
501         BLI_duplicatelist(&to->areabase, &from->areabase);
502         BLI_listbase_clear(&to->regionbase);
503         
504         s2 = to->vertbase.first;
505         for (s1 = from->vertbase.first; s1; s1 = s1->next, s2 = s2->next) {
506                 s1->newv = s2;
507         }
508         
509         for (se = to->edgebase.first; se; se = se->next) {
510                 se->v1 = se->v1->newv;
511                 se->v2 = se->v2->newv;
512                 sortscrvert(&(se->v1), &(se->v2));
513         }
514         
515         saf = from->areabase.first;
516         for (sa = to->areabase.first; sa; sa = sa->next, saf = saf->next) {
517                 sa->v1 = sa->v1->newv;
518                 sa->v2 = sa->v2->newv;
519                 sa->v3 = sa->v3->newv;
520                 sa->v4 = sa->v4->newv;
521
522                 BLI_listbase_clear(&sa->spacedata);
523                 BLI_listbase_clear(&sa->regionbase);
524                 BLI_listbase_clear(&sa->actionzones);
525                 BLI_listbase_clear(&sa->handlers);
526                 
527                 ED_area_data_copy(sa, saf, true);
528         }
529         
530         /* put at zero (needed?) */
531         for (s1 = from->vertbase.first; s1; s1 = s1->next)
532                 s1->newv = NULL;
533
534 }
535
536
537 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
538 /* -1 = not valid check */
539 /* used with join operator */
540 int area_getorientation(ScrArea *sa, ScrArea *sb)
541 {
542         ScrVert *sav1, *sav2, *sav3, *sav4;
543         ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
544
545         if (sa == NULL || sb == NULL) return -1;
546
547         sav1 = sa->v1;
548         sav2 = sa->v2;
549         sav3 = sa->v3;
550         sav4 = sa->v4;
551         sbv1 = sb->v1;
552         sbv2 = sb->v2;
553         sbv3 = sb->v3;
554         sbv4 = sb->v4;
555         
556         if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
557                 return 0;
558         }
559         else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
560                 return 1;
561         }
562         else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
563                 return 2;
564         }
565         else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
566                 return 3;
567         }
568         
569         return -1;
570 }
571
572 /* Helper function to join 2 areas, it has a return value, 0=failed 1=success
573  *  used by the split, join operators
574  */
575 int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
576 {
577         int dir;
578         
579         dir = area_getorientation(sa1, sa2);
580         /*printf("dir is : %i\n", dir);*/
581         
582         if (dir == -1) {
583                 if (sa1) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
584                 if (sa2) sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
585                 return 0;
586         }
587         
588         if (dir == 0) {
589                 sa1->v1 = sa2->v1;
590                 sa1->v2 = sa2->v2;
591                 screen_addedge(scr, sa1->v2, sa1->v3);
592                 screen_addedge(scr, sa1->v1, sa1->v4);
593         }
594         else if (dir == 1) {
595                 sa1->v2 = sa2->v2;
596                 sa1->v3 = sa2->v3;
597                 screen_addedge(scr, sa1->v1, sa1->v2);
598                 screen_addedge(scr, sa1->v3, sa1->v4);
599         }
600         else if (dir == 2) {
601                 sa1->v3 = sa2->v3;
602                 sa1->v4 = sa2->v4;
603                 screen_addedge(scr, sa1->v2, sa1->v3);
604                 screen_addedge(scr, sa1->v1, sa1->v4);
605         }
606         else if (dir == 3) {
607                 sa1->v1 = sa2->v1;
608                 sa1->v4 = sa2->v4;
609                 screen_addedge(scr, sa1->v1, sa1->v2);
610                 screen_addedge(scr, sa1->v3, sa1->v4);
611         }
612         
613         screen_delarea(C, scr, sa2);
614         removedouble_scrverts(scr);
615         sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
616         /* Update preview thumbnail */
617         BKE_icon_changed(scr->id.icon_id);
618
619         return 1;
620 }
621
622 void select_connected_scredge(bScreen *sc, ScrEdge *edge)
623 {
624         ScrEdge *se;
625         ScrVert *sv;
626         int oneselected;
627         char dir;
628         
629         /* select connected, only in the right direction */
630         /* 'dir' is the direction of EDGE */
631         
632         if (edge->v1->vec.x == edge->v2->vec.x) dir = 'v';
633         else dir = 'h';
634         
635         sv = sc->vertbase.first;
636         while (sv) {
637                 sv->flag = 0;
638                 sv = sv->next;
639         }
640         
641         edge->v1->flag = 1;
642         edge->v2->flag = 1;
643         
644         oneselected = 1;
645         while (oneselected) {
646                 se = sc->edgebase.first;
647                 oneselected = 0;
648                 while (se) {
649                         if (se->v1->flag + se->v2->flag == 1) {
650                                 if (dir == 'h') {
651                                         if (se->v1->vec.y == se->v2->vec.y) {
652                                                 se->v1->flag = se->v2->flag = 1;
653                                                 oneselected = 1;
654                                         }
655                                 }
656                                 if (dir == 'v') {
657                                         if (se->v1->vec.x == se->v2->vec.x) {
658                                                 se->v1->flag = se->v2->flag = 1;
659                                                 oneselected = 1;
660                                         }
661                                 }
662                         }
663                         se = se->next;
664                 }
665         }
666 }
667
668 /* test if screen vertices should be scaled */
669 static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
670 {
671         /* clamp Y size of header sized areas when expanding windows
672          * avoids annoying empty space around file menu */
673 #define USE_HEADER_SIZE_CLAMP
674
675         const int headery_init = ED_area_headersize();
676         ScrVert *sv = NULL;
677         ScrArea *sa;
678         int winsize_x_prev, winsize_y_prev;
679         float facx, facy, tempf, min[2], max[2];
680         
681         /* calculate size */
682         min[0] = min[1] = 20000.0f;
683         max[0] = max[1] = 0.0f;
684         
685         for (sv = sc->vertbase.first; sv; sv = sv->next) {
686                 const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
687                 minmax_v2v2_v2(min, max, fv);
688         }
689         
690         /* always make 0.0 left under */
691         for (sv = sc->vertbase.first; sv; sv = sv->next) {
692                 sv->vec.x -= min[0];
693                 sv->vec.y -= min[1];
694         }
695         
696         winsize_x_prev = (max[0] - min[0]) + 1;
697         winsize_y_prev = (max[1] - min[1]) + 1;
698
699
700 #ifdef USE_HEADER_SIZE_CLAMP
701 #define TEMP_BOTTOM 1
702 #define TEMP_TOP 2
703
704         /* if the window's Y axis grows, clamp header sized areas */
705         if (winsize_y_prev < winsize_y) {  /* growing? */
706                 const int headery_margin_max = headery_init + 4;
707                 for (sa = sc->areabase.first; sa; sa = sa->next) {
708                         ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
709                         sa->temp = 0;
710
711                         if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) {
712                                 if (sa->v2->vec.y == winsize_y_prev - 1) {
713                                         if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) {
714                                                 sa->temp = TEMP_TOP;
715                                         }
716                                 }
717                                 else if (sa->v1->vec.y == 0) {
718                                         if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) {
719                                                 sa->temp = TEMP_BOTTOM;
720                                         }
721                                 }
722                         }
723                 }
724         }
725 #endif
726
727
728         if (winsize_x_prev != winsize_x || winsize_y_prev != winsize_y) {
729                 facx = ((float)winsize_x - 1) / ((float)winsize_x_prev - 1);
730                 facy = ((float)winsize_y - 1) / ((float)winsize_y_prev - 1);
731                 
732                 /* make sure it fits! */
733                 for (sv = sc->vertbase.first; sv; sv = sv->next) {
734                         /* FIXME, this re-sizing logic is no good when re-sizing the window + redrawing [#24428]
735                          * need some way to store these as floats internally and re-apply from there. */
736                         tempf = ((float)sv->vec.x) * facx;
737                         sv->vec.x = (short)(tempf + 0.5f);
738                         //sv->vec.x += AREAGRID - 1;
739                         //sv->vec.x -=  (sv->vec.x % AREAGRID);
740
741                         CLAMP(sv->vec.x, 0, winsize_x - 1);
742                         
743                         tempf = ((float)sv->vec.y) * facy;
744                         sv->vec.y = (short)(tempf + 0.5f);
745                         //sv->vec.y += AREAGRID - 1;
746                         //sv->vec.y -=  (sv->vec.y % AREAGRID);
747
748                         CLAMP(sv->vec.y, 0, winsize_y - 1);
749                 }
750         }
751
752
753 #ifdef USE_HEADER_SIZE_CLAMP
754         if (winsize_y_prev < winsize_y) {  /* growing? */
755                 for (sa = sc->areabase.first; sa; sa = sa->next) {
756                         ScrEdge *se = NULL;
757
758                         if (sa->temp == 0)
759                                 continue;
760
761                         if (sa->v1 == sa->v2)
762                                 continue;
763
764                         /* adjust headery if verts are along the edge of window */
765                         if (sa->temp == TEMP_TOP) {
766                                 /* lower edge */
767                                 const int yval = sa->v2->vec.y - headery_init;
768                                 se = screen_findedge(sc, sa->v4, sa->v1);
769                                 if (se != NULL) {
770                                         select_connected_scredge(sc, se);
771                                 }
772                                 for (sv = sc->vertbase.first; sv; sv = sv->next) {
773                                         if (sv != sa->v2 && sv != sa->v3) {
774                                                 if (sv->flag) {
775                                                         sv->vec.y = yval;
776                                                 }
777                                         }
778                                 }
779                         }
780                         else {
781                                 /* upper edge */
782                                 const int yval = sa->v1->vec.y + headery_init;
783                                 se = screen_findedge(sc, sa->v2, sa->v3);
784                                 if (se != NULL) {
785                                         select_connected_scredge(sc, se);
786                                 }
787                                 for (sv = sc->vertbase.first; sv; sv = sv->next) {
788                                         if (sv != sa->v1 && sv != sa->v4) {
789                                                 if (sv->flag) {
790                                                         sv->vec.y = yval;
791                                                 }
792                                         }
793                                 }
794                         }
795                 }
796         }
797
798 #undef USE_HEADER_SIZE_CLAMP
799 #undef TEMP_BOTTOM
800 #undef TEMP_TOP
801 #endif
802
803
804         /* test for collapsed areas. This could happen in some blender version... */
805         /* ton: removed option now, it needs Context... */
806         
807         /* make each window at least ED_area_headersize() high */
808         for (sa = sc->areabase.first; sa; sa = sa->next) {
809                 int headery = headery_init;
810                 
811                 /* adjust headery if verts are along the edge of window */
812                 if (sa->v1->vec.y > 0)
813                         headery += U.pixelsize;
814                 if (sa->v2->vec.y < winsize_y - 1)
815                         headery += U.pixelsize;
816                 
817                 if (sa->v2->vec.y - sa->v1->vec.y + 1 < headery) {
818                         /* lower edge */
819                         ScrEdge *se = screen_findedge(sc, sa->v4, sa->v1);
820                         if (se && sa->v1 != sa->v2) {
821                                 int yval;
822                                 
823                                 select_connected_scredge(sc, se);
824                                 
825                                 /* all selected vertices get the right offset */
826                                 yval = sa->v2->vec.y - headery + 1;
827                                 for (sv = sc->vertbase.first; sv; sv = sv->next) {
828                                         /* if is a collapsed area */
829                                         if (sv != sa->v2 && sv != sa->v3) {
830                                                 if (sv->flag) {
831                                                         sv->vec.y = yval;
832                                                 }
833                                         }
834                                 }
835                         }
836                 }
837         }
838         
839 }
840
841
842 /* ****************** EXPORTED API TO OTHER MODULES *************************** */
843
844 bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
845 {
846         bScreen *newsc;
847         
848         if (sc->state != SCREENNORMAL) return NULL;  /* XXX handle this case! */
849         
850         /* make new empty screen: */
851         newsc = ED_screen_add(win, sc->scene, sc->id.name + 2);
852         /* copy all data */
853         screen_copy(newsc, sc);
854
855         return newsc;
856 }
857
858 /* screen sets cursor based on swinid */
859 static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
860 {
861         for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) {
862                 for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
863                         if (ar->swinid == swinid) {
864                                 if (swin_changed || (ar->type && ar->type->event_cursor)) {
865                                         if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) {
866                                                 return;
867                                         }
868                                         ED_region_cursor_set(win, sa, ar);
869                                 }
870                                 return;
871                         }
872                 }
873         }
874 }
875
876 void ED_screen_do_listen(bContext *C, wmNotifier *note)
877 {
878         wmWindow *win = CTX_wm_window(C);
879         
880         /* generic notes */
881         switch (note->category) {
882                 case NC_WM:
883                         if (note->data == ND_FILEREAD)
884                                 win->screen->do_draw = true;
885                         break;
886                 case NC_WINDOW:
887                         win->screen->do_draw = true;
888                         break;
889                 case NC_SCREEN:
890                         if (note->action == NA_EDITED)
891                                 win->screen->do_draw = win->screen->do_refresh = true;
892                         break;
893                 case NC_SCENE:
894                         if (note->data == ND_MODE)
895                                 region_cursor_set(win, note->swinid, true);
896                         break;
897         }
898 }
899
900 /* helper call for below, dpi changes headers */
901 static void screen_refresh_headersizes(void)
902 {
903         const ListBase *lb = BKE_spacetypes_list();
904         SpaceType *st;
905         
906         for (st = lb->first; st; st = st->next) {
907                 ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_HEADER);
908                 if (art) art->prefsizey = ED_area_headersize();
909         }
910 }
911
912 /* make this screen usable */
913 /* for file read and first use, for scaling window, area moves */
914 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
915 {       
916         /* exception for bg mode, we only need the screen context */
917         if (!G.background) {
918                 const int winsize_x = WM_window_pixels_x(win);
919                 const int winsize_y = WM_window_pixels_y(win);
920                 ScrArea *sa;
921                 rcti winrct;
922         
923                 winrct.xmin = 0;
924                 winrct.xmax = winsize_x - 1;
925                 winrct.ymin = 0;
926                 winrct.ymax = winsize_y - 1;
927                 
928                 /* header size depends on DPI, let's verify */
929                 screen_refresh_headersizes();
930                 
931                 screen_test_scale(win->screen, winsize_x, winsize_y);
932                 
933                 if (win->screen->mainwin == 0) {
934                         win->screen->mainwin = wm_subwindow_open(win, &winrct, false);
935                 }
936                 else {
937                         wm_subwindow_position(win, win->screen->mainwin, &winrct, false);
938                 }
939                 
940                 for (sa = win->screen->areabase.first; sa; sa = sa->next) {
941                         /* set spacetype and region callbacks, calls init() */
942                         /* sets subwindows for regions, adds handlers */
943                         ED_area_initialize(wm, win, sa);
944                 }
945         
946                 /* wake up animtimer */
947                 if (win->screen->animtimer)
948                         WM_event_timer_sleep(wm, win, win->screen->animtimer, false);
949         }
950
951         if (G.debug & G_DEBUG_EVENTS) {
952                 printf("%s: set screen\n", __func__);
953         }
954         win->screen->do_refresh = false;
955
956         win->screen->context = ed_screen_context;
957 }
958
959 /* file read, set all screens, ... */
960 void ED_screens_initialize(wmWindowManager *wm)
961 {
962         wmWindow *win;
963         
964         for (win = wm->windows.first; win; win = win->next) {
965                 
966                 if (win->screen == NULL)
967                         win->screen = G.main->screen.first;
968                 
969                 ED_screen_refresh(wm, win);
970         }
971 }
972
973
974 /* *********** exit calls are for closing running stuff ******** */
975
976 void ED_region_exit(bContext *C, ARegion *ar)
977 {
978         wmWindowManager *wm = CTX_wm_manager(C);
979         wmWindow *win = CTX_wm_window(C);
980         ARegion *prevar = CTX_wm_region(C);
981
982         if (ar->type && ar->type->exit)
983                 ar->type->exit(wm, ar);
984
985         CTX_wm_region_set(C, ar);
986
987         WM_event_remove_handlers(C, &ar->handlers);
988         WM_event_modal_handler_region_replace(win, ar, NULL);
989         if (ar->swinid) {
990                 wm_subwindow_close(win, ar->swinid);
991                 ar->swinid = 0;
992         }
993
994         if (ar->headerstr) {
995                 MEM_freeN(ar->headerstr);
996                 ar->headerstr = NULL;
997         }
998         
999         if (ar->regiontimer) {
1000                 WM_event_remove_timer(wm, win, ar->regiontimer);
1001                 ar->regiontimer = NULL;
1002         }
1003
1004         CTX_wm_region_set(C, prevar);
1005 }
1006
1007 void ED_area_exit(bContext *C, ScrArea *sa)
1008 {
1009         wmWindowManager *wm = CTX_wm_manager(C);
1010         wmWindow *win = CTX_wm_window(C);
1011         ScrArea *prevsa = CTX_wm_area(C);
1012         ARegion *ar;
1013
1014         if (sa->type && sa->type->exit)
1015                 sa->type->exit(wm, sa);
1016
1017         CTX_wm_area_set(C, sa);
1018
1019         for (ar = sa->regionbase.first; ar; ar = ar->next)
1020                 ED_region_exit(C, ar);
1021
1022         WM_event_remove_handlers(C, &sa->handlers);
1023         WM_event_modal_handler_area_replace(win, sa, NULL);
1024
1025         CTX_wm_area_set(C, prevsa);
1026 }
1027
1028 void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
1029 {
1030         wmWindowManager *wm = CTX_wm_manager(C);
1031         wmWindow *prevwin = CTX_wm_window(C);
1032         ScrArea *sa;
1033         ARegion *ar;
1034
1035         CTX_wm_window_set(C, window);
1036         
1037         if (screen->animtimer)
1038                 WM_event_remove_timer(wm, window, screen->animtimer);
1039         screen->animtimer = NULL;
1040         screen->scrubbing = false;
1041
1042         if (screen->mainwin)
1043                 wm_subwindow_close(window, screen->mainwin);
1044         screen->mainwin = 0;
1045         screen->subwinactive = 0;
1046         
1047         for (ar = screen->regionbase.first; ar; ar = ar->next)
1048                 ED_region_exit(C, ar);
1049
1050         for (sa = screen->areabase.first; sa; sa = sa->next)
1051                 ED_area_exit(C, sa);
1052
1053         /* mark it available for use for other windows */
1054         screen->winid = 0;
1055         
1056         if (prevwin->screen->temp == 0) {
1057                 /* use previous window if possible */
1058                 CTX_wm_window_set(C, prevwin);
1059         }
1060         else {
1061                 /* none otherwise */
1062                 CTX_wm_window_set(C, NULL);
1063         }
1064         
1065 }
1066
1067 /* *********************************** */
1068
1069 /* case when on area-edge or in azones, or outside window */
1070 static void screen_cursor_set(wmWindow *win, wmEvent *event)
1071 {
1072         const int winsize_x = WM_window_pixels_x(win);
1073         const int winsize_y = WM_window_pixels_y(win);
1074
1075         AZone *az = NULL;
1076         ScrArea *sa;
1077         
1078         for (sa = win->screen->areabase.first; sa; sa = sa->next)
1079                 if ((az = is_in_area_actionzone(sa, &event->x)))
1080                         break;
1081         
1082         if (sa) {
1083                 if (az->type == AZONE_AREA)
1084                         WM_cursor_set(win, CURSOR_EDIT);
1085                 else if (az->type == AZONE_REGION) {
1086                         if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT)
1087                                 WM_cursor_set(win, CURSOR_X_MOVE);
1088                         else
1089                                 WM_cursor_set(win, CURSOR_Y_MOVE);
1090                 }
1091         }
1092         else {
1093                 ScrEdge *actedge = screen_find_active_scredge(win->screen, winsize_x, winsize_y, event->x, event->y);
1094                 
1095                 if (actedge) {
1096                         if (scredge_is_horizontal(actedge))
1097                                 WM_cursor_set(win, CURSOR_Y_MOVE);
1098                         else
1099                                 WM_cursor_set(win, CURSOR_X_MOVE);
1100                 }
1101                 else
1102                         WM_cursor_set(win, CURSOR_STD);
1103         }
1104 }
1105
1106
1107 /* called in wm_event_system.c. sets state vars in screen, cursors */
1108 /* event type is mouse move */
1109 void ED_screen_set_subwinactive(bContext *C, wmEvent *event)
1110 {
1111         wmWindow *win = CTX_wm_window(C);
1112         
1113         if (win->screen) {
1114                 bScreen *scr = win->screen;
1115                 ScrArea *sa;
1116                 ARegion *ar;
1117                 int oldswin = scr->subwinactive;
1118
1119                 for (sa = scr->areabase.first; sa; sa = sa->next) {
1120                         if (event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
1121                                 if (event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
1122                                         if (NULL == is_in_area_actionzone(sa, &event->x))
1123                                                 break;
1124                 }
1125                 if (sa) {
1126                         /* make overlap active when mouse over */
1127                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1128                                 if (BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) {
1129                                         scr->subwinactive = ar->swinid;
1130                                         break;
1131                                 }
1132                         }
1133                 }
1134                 else
1135                         scr->subwinactive = scr->mainwin;
1136                 
1137                 /* check for redraw headers */
1138                 if (oldswin != scr->subwinactive) {
1139
1140                         for (sa = scr->areabase.first; sa; sa = sa->next) {
1141                                 bool do_draw = false;
1142                                 
1143                                 for (ar = sa->regionbase.first; ar; ar = ar->next)
1144                                         if (ar->swinid == oldswin || ar->swinid == scr->subwinactive)
1145                                                 do_draw = true;
1146                                 
1147                                 if (do_draw) {
1148                                         for (ar = sa->regionbase.first; ar; ar = ar->next)
1149                                                 if (ar->regiontype == RGN_TYPE_HEADER)
1150                                                         ED_region_tag_redraw(ar);
1151                                 }
1152                         }
1153                 }
1154                 
1155                 /* cursors, for time being set always on edges, otherwise aregion doesnt switch */
1156                 if (scr->subwinactive == scr->mainwin) {
1157                         screen_cursor_set(win, event);
1158                 }
1159                 else {
1160                         /* notifier invokes freeing the buttons... causing a bit too much redraws */
1161                         if (oldswin != scr->subwinactive) {
1162                                 region_cursor_set(win, scr->subwinactive, true);
1163
1164                                 /* this used to be a notifier, but needs to be done immediate
1165                                  * because it can undo setting the right button as active due
1166                                  * to delayed notifier handling */
1167                                 UI_screen_free_active_but(C, win->screen);
1168                         }
1169                         else
1170                                 region_cursor_set(win, scr->subwinactive, false);
1171                 }
1172         }
1173 }
1174
1175 int ED_screen_area_active(const bContext *C)
1176 {
1177         wmWindow *win = CTX_wm_window(C);
1178         bScreen *sc = CTX_wm_screen(C);
1179         ScrArea *sa = CTX_wm_area(C);
1180
1181         if (win && sc && sa) {
1182                 AZone *az = is_in_area_actionzone(sa, &win->eventstate->x);
1183                 ARegion *ar;
1184                 
1185                 if (az && az->type == AZONE_REGION)
1186                         return 1;
1187                 
1188                 for (ar = sa->regionbase.first; ar; ar = ar->next)
1189                         if (ar->swinid == sc->subwinactive)
1190                                 return 1;
1191         }
1192         return 0;
1193 }
1194
1195 /**
1196  * operator call, WM + Window + screen already existed before
1197  *
1198  * \warning Do NOT call in area/region queues!
1199  * \returns success.
1200  */
1201 bool ED_screen_set(bContext *C, bScreen *sc)
1202 {
1203         Main *bmain = CTX_data_main(C);
1204         wmWindowManager *wm = CTX_wm_manager(C);
1205         wmWindow *win = CTX_wm_window(C);
1206         bScreen *oldscreen = CTX_wm_screen(C);
1207         
1208         /* validate screen, it's called with notifier reference */
1209         if (BLI_findindex(&bmain->screen, sc) == -1) {
1210                 return true;
1211         }
1212
1213         if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
1214                 /* find associated full */
1215                 bScreen *sc1;
1216                 for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) {
1217                         ScrArea *sa = sc1->areabase.first;
1218                         if (sa->full == sc) {
1219                                 sc = sc1;
1220                                 break;
1221                         }
1222                 }
1223         }
1224
1225         /* check for valid winid */
1226         if (sc->winid != 0 && sc->winid != win->winid) {
1227                 return false;
1228         }
1229         
1230         if (oldscreen != sc) {
1231                 wmTimer *wt = oldscreen->animtimer;
1232                 ScrArea *sa;
1233                 Scene *oldscene = oldscreen->scene;
1234
1235                 /* remove handlers referencing areas in old screen */
1236                 for (sa = oldscreen->areabase.first; sa; sa = sa->next) {
1237                         WM_event_remove_area_handler(&win->modalhandlers, sa);
1238                 }
1239
1240                 /* we put timer to sleep, so screen_exit has to think there's no timer */
1241                 oldscreen->animtimer = NULL;
1242                 if (wt) {
1243                         WM_event_timer_sleep(wm, win, wt, true);
1244                 }
1245
1246                 ED_screen_exit(C, win, oldscreen);
1247
1248                 /* Same scene, "transfer" playback to new screen. */
1249                 if (wt) {
1250                         if (oldscene == sc->scene) {
1251                                 sc->animtimer = wt;
1252                         }
1253                         /* Else, stop playback. */
1254                         else {
1255                                 oldscreen->animtimer = wt;
1256                                 ED_screen_animation_play(C, 0, 0);
1257                         }
1258                 }
1259
1260                 win->screen = sc;
1261                 CTX_wm_window_set(C, win);  // stores C->wm.screen... hrmf
1262                 
1263                 /* prevent multiwin errors */
1264                 sc->winid = win->winid;
1265                 
1266                 ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
1267                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1268                 WM_event_add_notifier(C, NC_SCREEN | ND_SCREENSET, sc);
1269                 
1270                 /* makes button hilites work */
1271                 WM_event_add_mousemove(C);
1272
1273                 /* Needed to make sure all the derivedMeshes are
1274                  * up-to-date before viewport starts acquiring this.
1275                  *
1276                  * This is needed in cases when, for example, boolean
1277                  * modifier uses operant from invisible layer.
1278                  * Without this trick boolean wouldn't apply correct.
1279                  *
1280                  * Quite the same happens when setting screen's scene,
1281                  * so perhaps this is in fact correct thing to do.
1282                  */
1283                 if (oldscene != sc->scene) {
1284                         BKE_scene_set_background(bmain, sc->scene);
1285                 }
1286
1287                 /* Always do visible update since it's possible new screen will
1288                  * have different layers visible in 3D view-ports.
1289                  * This is possible because of view3d.lock_camera_and_layers option.
1290                  */
1291                 DAG_on_visible_update(bmain, false);
1292         }
1293
1294         return true;
1295 }
1296
1297 static bool ed_screen_used(wmWindowManager *wm, bScreen *sc)
1298 {
1299         wmWindow *win;
1300
1301         for (win = wm->windows.first; win; win = win->next) {
1302                 if (win->screen == sc) {
1303                         return true;
1304                 }
1305
1306                 if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) {
1307                         ScrArea *sa = win->screen->areabase.first;
1308                         if (sa->full == sc) {
1309                                 return true;
1310                         }
1311                 }
1312         }
1313
1314         return false;
1315 }
1316
1317 /* only call outside of area/region loops */
1318 bool ED_screen_delete(bContext *C, bScreen *sc)
1319 {
1320         Main *bmain = CTX_data_main(C);
1321         wmWindowManager *wm = CTX_wm_manager(C);
1322         wmWindow *win = CTX_wm_window(C);
1323         bScreen *newsc;
1324         
1325         /* don't allow deleting temp fullscreens for now */
1326         if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
1327                 return false;
1328         }
1329
1330         /* screen can only be in use by one window at a time, so as
1331          * long as we are able to find a screen that is unused, we
1332          * can safely assume ours is not in use anywhere an delete it */
1333
1334         for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
1335                 if (!ed_screen_used(wm, newsc) && !newsc->temp)
1336                         break;
1337         
1338         if (!newsc) {
1339                 for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
1340                         if (!ed_screen_used(wm, newsc) && !newsc->temp)
1341                                 break;
1342         }
1343
1344         if (!newsc) {
1345                 return false;
1346         }
1347
1348         ED_screen_set(C, newsc);
1349
1350         if (win->screen != sc) {
1351                 BKE_libblock_free(bmain, sc);
1352                 return true;
1353         }
1354         else {
1355                 return false;
1356         }
1357 }
1358
1359 static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, View3D *v3d)
1360 {
1361         /* fix any cameras that are used in the 3d view but not in the scene */
1362         BKE_screen_view3d_sync(v3d, scene);
1363
1364         if (!v3d->camera || !BKE_scene_base_find(scene, v3d->camera)) {
1365                 v3d->camera = BKE_scene_camera_find(sc->scene);
1366                 // XXX if (sc == curscreen) handle_view3d_lock();
1367                 if (!v3d->camera) {
1368                         ARegion *ar;
1369                         ListBase *regionbase;
1370                         
1371                         /* regionbase is in different place depending if space is active */
1372                         if (v3d == sa->spacedata.first)
1373                                 regionbase = &sa->regionbase;
1374                         else
1375                                 regionbase = &v3d->regionbase;
1376                                 
1377                         for (ar = regionbase->first; ar; ar = ar->next) {
1378                                 if (ar->regiontype == RGN_TYPE_WINDOW) {
1379                                         RegionView3D *rv3d = ar->regiondata;
1380                                         if (rv3d->persp == RV3D_CAMOB) {
1381                                                 rv3d->persp = RV3D_PERSP;
1382                                         }
1383                                 }
1384                         }
1385                 }
1386         }
1387 }
1388
1389 /* only call outside of area/region loops */
1390 void ED_screen_set_scene(bContext *C, bScreen *screen, Scene *scene)
1391 {
1392         Main *bmain = CTX_data_main(C);
1393         bScreen *sc;
1394
1395         if (screen == NULL)
1396                 return;
1397         
1398         if (ed_screen_used(CTX_wm_manager(C), screen))
1399                 ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO);
1400
1401         for (sc = bmain->screen.first; sc; sc = sc->id.next) {
1402                 if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
1403                         
1404                         if (scene != sc->scene) {
1405                                 /* all areas endlocalview */
1406                                 // XXX  ScrArea *sa = sc->areabase.first;
1407                                 //      while (sa) {
1408                                 //              endlocalview(sa);
1409                                 //              sa = sa->next;
1410                                 //      }
1411                                 sc->scene = scene;
1412                         }
1413                         
1414                 }
1415         }
1416         
1417         //  copy_view3d_lock(0);        /* space.c */
1418         
1419         /* are there cameras in the views that are not in the scene? */
1420         for (sc = bmain->screen.first; sc; sc = sc->id.next) {
1421                 if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
1422                         ScrArea *sa = sc->areabase.first;
1423                         while (sa) {
1424                                 SpaceLink *sl = sa->spacedata.first;
1425                                 while (sl) {
1426                                         if (sl->spacetype == SPACE_VIEW3D) {
1427                                                 View3D *v3d = (View3D *) sl;
1428                                                 ed_screen_set_3dview_camera(scene, sc, sa, v3d);
1429
1430                                         }
1431                                         sl = sl->next;
1432                                 }
1433                                 sa = sa->next;
1434                         }
1435                 }
1436         }
1437         
1438         CTX_data_scene_set(C, scene);
1439         BKE_scene_set_background(bmain, scene);
1440         DAG_on_visible_update(bmain, false);
1441         
1442         ED_render_engine_changed(bmain);
1443         ED_update_for_newframe(bmain, scene, 1);
1444         
1445         /* complete redraw */
1446         WM_event_add_notifier(C, NC_WINDOW, NULL);
1447         
1448 }
1449
1450 /**
1451  * \note Only call outside of area/region loops
1452  * \return true if successful
1453  */
1454 bool ED_screen_delete_scene(bContext *C, Scene *scene)
1455 {
1456         Main *bmain = CTX_data_main(C);
1457         Scene *newscene;
1458
1459         if (scene->id.prev)
1460                 newscene = scene->id.prev;
1461         else if (scene->id.next)
1462                 newscene = scene->id.next;
1463         else
1464                 return false;
1465
1466         ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
1467
1468         BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
1469
1470         BKE_libblock_free(bmain, scene);
1471
1472         return true;
1473 }
1474
1475 ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
1476 {
1477         wmWindow *win = CTX_wm_window(C);
1478         bScreen *screen = CTX_wm_screen(C);
1479         ScrArea *newsa = NULL;
1480
1481         if (!sa || sa->full == NULL) {
1482                 newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
1483         }
1484         
1485         if (!newsa) {
1486                 if (sa->full && (screen->state == SCREENMAXIMIZED)) {
1487                         /* if this has been called from the temporary info header generated in
1488                          * temp fullscreen layouts, find the correct fullscreen area to change
1489                          * to create a new space inside */
1490                         for (newsa = screen->areabase.first; newsa; newsa = newsa->next) {
1491                                 if (!(sa->flag & AREA_TEMP_INFO))
1492                                         break;
1493                         }
1494                 }
1495                 else {
1496                         newsa = sa;
1497                 }
1498         }
1499
1500         BLI_assert(newsa);
1501
1502         if (sa && (sa->spacetype != type)) {
1503                 newsa->flag |= AREA_FLAG_TEMP_TYPE;
1504         }
1505         else {
1506                 newsa->flag &= ~AREA_FLAG_TEMP_TYPE;
1507         }
1508
1509         ED_area_newspace(C, newsa, type, (newsa->flag & AREA_FLAG_TEMP_TYPE));
1510
1511         return newsa;
1512 }
1513
1514 /**
1515  * \a was_prev_temp for the case previous space was a temporary fullscreen as well
1516  */
1517 void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
1518 {
1519         BLI_assert(sa->full);
1520
1521         if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
1522                 /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
1523                 ED_area_prevspace(C, sa);
1524         }
1525         else {
1526                 ED_screen_restore_temp_type(C, sa);
1527         }
1528 }
1529
1530 void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
1531 {
1532         /* incase nether functions below run */
1533         ED_area_tag_redraw(sa);
1534
1535         if (sa->flag & AREA_FLAG_TEMP_TYPE) {
1536                 ED_area_prevspace(C, sa);
1537                 sa->flag &= ~AREA_FLAG_TEMP_TYPE;
1538         }
1539
1540         if (sa->full) {
1541                 ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
1542         }
1543 }
1544
1545 /* restore a screen / area back to default operation, after temp fullscreen modes */
1546 void ED_screen_full_restore(bContext *C, ScrArea *sa)
1547 {
1548         wmWindow *win = CTX_wm_window(C);
1549         SpaceLink *sl = sa->spacedata.first;
1550         bScreen *screen = CTX_wm_screen(C);
1551         short state = (screen ? screen->state : SCREENMAXIMIZED);
1552         
1553         /* if fullscreen area has a temporary space (such as a file browser or fullscreen render
1554          * overlaid on top of an existing setup) then return to the previous space */
1555         
1556         if (sl->next) {
1557                 if (sa->flag & AREA_FLAG_TEMP_TYPE) {
1558                         ED_screen_full_prevspace(C, sa);
1559                 }
1560                 else {
1561                         ED_screen_state_toggle(C, win, sa, state);
1562                 }
1563                 /* warning: 'sa' may be freed */
1564         }
1565         /* otherwise just tile the area again */
1566         else {
1567                 ED_screen_state_toggle(C, win, sa, state);
1568         }
1569 }
1570
1571 /**
1572  * this function toggles: if area is maximized/full then the parent will be restored
1573  *
1574  * \warning \a sa may be freed.
1575  */
1576 ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
1577 {
1578         wmWindowManager *wm = CTX_wm_manager(C);
1579         bScreen *sc, *oldscreen;
1580         ARegion *ar;
1581
1582         if (sa) {
1583                 /* ensure we don't have a button active anymore, can crash when
1584                  * switching screens with tooltip open because region and tooltip
1585                  * are no longer in the same screen */
1586                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
1587                         UI_blocklist_free(C, &ar->uiblocks);
1588
1589                         if (ar->regiontimer) {
1590                                 WM_event_remove_timer(wm, NULL, ar->regiontimer);
1591                                 ar->regiontimer = NULL;
1592                         }
1593                 }
1594
1595                 /* prevent hanging header prints */
1596                 ED_area_headerprint(sa, NULL);
1597         }
1598
1599         if (sa && sa->full) {
1600                 /* restoring back to SCREENNORMAL */
1601                 ScrArea *old;
1602
1603                 sc = sa->full;       /* the old screen to restore */
1604                 oldscreen = win->screen; /* the one disappearing */
1605
1606                 sc->state = SCREENNORMAL;
1607
1608                 /* find old area */
1609                 for (old = sc->areabase.first; old; old = old->next)
1610                         if (old->full) break;
1611                 if (old == NULL) {
1612                         if (G.debug & G_DEBUG)
1613                                 printf("%s: something wrong in areafullscreen\n", __func__);
1614                         return NULL;
1615                 }
1616
1617                 if (state == SCREENFULL) {
1618                         /* restore the old side panels/header visibility */
1619                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1620                                 ar->flag = ar->flagfullscreen;
1621                         }
1622                 }
1623
1624                 ED_area_data_swap(old, sa);
1625                 if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO;
1626                 old->full = NULL;
1627
1628                 /* animtimer back */
1629                 sc->animtimer = oldscreen->animtimer;
1630                 oldscreen->animtimer = NULL;
1631
1632                 ED_screen_set(C, sc);
1633
1634                 BKE_screen_free(oldscreen);
1635                 BKE_libblock_free(CTX_data_main(C), oldscreen);
1636
1637                 /* After we've restored back to SCREENNORMAL, we have to wait with
1638                  * screen handling as it uses the area coords which aren't updated yet.
1639                  * Without doing so, the screen handling gets wrong area coords,
1640                  * which in worst case can lead to crashes (see T43139) */
1641                 sc->skip_handling = true;
1642         }
1643         else {
1644                 /* change from SCREENNORMAL to new state */
1645                 ScrArea *newa;
1646                 char newname[MAX_ID_NAME - 2];
1647
1648                 oldscreen = win->screen;
1649
1650                 oldscreen->state = state;
1651                 BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
1652                 sc = ED_screen_add(win, oldscreen->scene, newname);
1653                 sc->state = state;
1654                 sc->redraws_flag = oldscreen->redraws_flag;
1655                 sc->temp = oldscreen->temp;
1656
1657                 /* timer */
1658                 sc->animtimer = oldscreen->animtimer;
1659                 oldscreen->animtimer = NULL;
1660
1661                 /* use random area when we have no active one, e.g. when the
1662                  * mouse is outside of the window and we open a file browser */
1663                 if (!sa)
1664                         sa = oldscreen->areabase.first;
1665
1666                 if (state == SCREENMAXIMIZED) {
1667                         /* returns the top small area */
1668                         newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
1669                         ED_area_newspace(C, newa, SPACE_INFO, false);
1670
1671                         /* copy area */
1672                         newa = newa->prev;
1673                         ED_area_data_swap(newa, sa);
1674                         sa->flag |= AREA_TEMP_INFO;
1675
1676                         sa->full = oldscreen;
1677                         newa->full = oldscreen;
1678                         newa->next->full = oldscreen; // XXX
1679                 }
1680                 else if (state == SCREENFULL) {
1681                         newa = (ScrArea *)sc->areabase.first;
1682
1683                         /* copy area */
1684                         ED_area_data_swap(newa, sa);
1685                         newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
1686
1687                         /* temporarily hide the side panels/header */
1688                         for (ar = newa->regionbase.first; ar; ar = ar->next) {
1689                                 ar->flagfullscreen = ar->flag;
1690
1691                                 if (ELEM(ar->regiontype,
1692                                          RGN_TYPE_UI,
1693                                          RGN_TYPE_HEADER,
1694                                          RGN_TYPE_TOOLS))
1695                                 {
1696                                         ar->flag |= RGN_FLAG_HIDDEN;
1697                                 }
1698                         }
1699
1700                         sa->full = oldscreen;
1701                         newa->full = oldscreen;
1702                 }
1703                 else {
1704                         BLI_assert(false);
1705                 }
1706
1707                 ED_screen_set(C, sc);
1708         }
1709
1710         /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
1711         CTX_wm_area_set(C, sc->areabase.first);
1712
1713         return sc->areabase.first;
1714 }
1715
1716 /* update frame rate info for viewport drawing */
1717 void ED_refresh_viewport_fps(bContext *C)
1718 {
1719         wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
1720         Scene *scene = CTX_data_scene(C);
1721         
1722         /* is anim playback running? */
1723         if (animtimer && (U.uiflag & USER_SHOW_FPS)) {
1724                 ScreenFrameRateInfo *fpsi = scene->fps_info;
1725                 
1726                 /* if there isn't any info, init it first */
1727                 if (fpsi == NULL)
1728                         fpsi = scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo), "refresh_viewport_fps fps_info");
1729                 
1730                 /* update the values */
1731                 fpsi->redrawtime = fpsi->lredrawtime;
1732                 fpsi->lredrawtime = animtimer->ltime;
1733         }
1734         else {
1735                 /* playback stopped or shouldn't be running */
1736                 if (scene->fps_info)
1737                         MEM_freeN(scene->fps_info);
1738                 scene->fps_info = NULL;
1739         }
1740 }
1741
1742 /* redraws: uses defines from stime->redraws 
1743  * enable: 1 - forward on, -1 - backwards on, 0 - off
1744  */
1745 void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync, int enable)
1746 {
1747         bScreen *screen = CTX_wm_screen(C);
1748         wmWindowManager *wm = CTX_wm_manager(C);
1749         wmWindow *win = CTX_wm_window(C);
1750         Scene *scene = CTX_data_scene(C);
1751         bScreen *stopscreen = ED_screen_animation_playing(wm);
1752         
1753         if (stopscreen) {
1754                 WM_event_remove_timer(wm, win, stopscreen->animtimer);
1755                 stopscreen->animtimer = NULL;
1756         }
1757         
1758         if (enable) {
1759                 ScreenAnimData *sad = MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData");
1760                 
1761                 screen->animtimer = WM_event_add_timer(wm, win, TIMER0, (1.0 / FPS));
1762                 
1763                 sad->ar = CTX_wm_region(C);
1764                 /* if startframe is larger than current frame, we put currentframe on startframe.
1765                  * note: first frame then is not drawn! (ton) */
1766                 if (PRVRANGEON) {
1767                         if (scene->r.psfra > scene->r.cfra) {
1768                                 sad->sfra = scene->r.cfra;
1769                                 scene->r.cfra = scene->r.psfra;
1770                         }
1771                         else
1772                                 sad->sfra = scene->r.cfra;
1773                 }
1774                 else {
1775                         if (scene->r.sfra > scene->r.cfra) {
1776                                 sad->sfra = scene->r.cfra;
1777                                 scene->r.cfra = scene->r.sfra;
1778                         }
1779                         else
1780                                 sad->sfra = scene->r.cfra;
1781                 }
1782                 sad->redraws = redraws;
1783                 sad->refresh = refresh;
1784                 sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
1785                 sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
1786
1787                 ScrArea *sa = CTX_wm_area(C);
1788
1789                 char spacetype = -1;
1790
1791                 if (sa)
1792                         spacetype = sa->spacetype;
1793
1794                 sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
1795
1796                 screen->animtimer->customdata = sad;
1797                 
1798         }
1799
1800         /* notifier catched by top header, for button */
1801         WM_event_add_notifier(C, NC_SCREEN | ND_ANIMPLAY, NULL);
1802 }
1803
1804 /* helper for screen_animation_play() - only to be used for TimeLine */
1805 static ARegion *time_top_left_3dwindow(bScreen *screen)
1806 {
1807         ARegion *aret = NULL;
1808         ScrArea *sa;
1809         int min = 10000;
1810         
1811         for (sa = screen->areabase.first; sa; sa = sa->next) {
1812                 if (sa->spacetype == SPACE_VIEW3D) {
1813                         ARegion *ar;
1814                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1815                                 if (ar->regiontype == RGN_TYPE_WINDOW) {
1816                                         if (ar->winrct.xmin - ar->winrct.ymin < min) {
1817                                                 aret = ar;
1818                                                 min = ar->winrct.xmin - ar->winrct.ymin;
1819                                         }
1820                                 }
1821                         }
1822                 }
1823         }
1824
1825         return aret;
1826 }
1827
1828 void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh)
1829 {
1830         if (screen && screen->animtimer) {
1831                 wmTimer *wt = screen->animtimer;
1832                 ScreenAnimData *sad = wt->customdata;
1833                 
1834                 sad->redraws = redraws;
1835                 sad->refresh = refresh;
1836                 sad->ar = NULL;
1837                 if (redraws & TIME_REGION)
1838                         sad->ar = time_top_left_3dwindow(screen);
1839         }
1840 }
1841
1842 /* results in fully updated anim system
1843  * screen can be NULL */
1844 void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
1845 {
1846 #ifdef DURIAN_CAMERA_SWITCH
1847         void *camera = BKE_scene_camera_switch_find(scene);
1848         if (camera && scene->camera != camera) {
1849                 bScreen *sc;
1850                 scene->camera = camera;
1851                 /* are there cameras in the views that are not in the scene? */
1852                 for (sc = bmain->screen.first; sc; sc = sc->id.next) {
1853                         BKE_screen_view3d_scene_sync(sc);
1854                 }
1855         }
1856 #endif
1857         
1858         ED_clip_update_frame(bmain, scene->r.cfra);
1859
1860         /* this function applies the changes too */
1861         BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene);
1862
1863         /* composite */
1864         if (scene->use_nodes && scene->nodetree)
1865                 ntreeCompositTagAnimated(scene->nodetree);
1866         
1867         /* update animated texture nodes */
1868         {
1869                 Tex *tex;
1870                 for (tex = bmain->tex.first; tex; tex = tex->id.next) {
1871                         if (tex->use_nodes && tex->nodetree) {
1872                                 ntreeTexTagAnimated(tex->nodetree);
1873                         }
1874                 }
1875         }
1876         
1877 }
1878
1879 /*
1880  * return true if any active area requires to see in 3D
1881  */
1882 bool ED_screen_stereo3d_required(bScreen *screen)
1883 {
1884         ScrArea *sa;
1885         Scene *sce = screen->scene;
1886         const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
1887
1888         for (sa = screen->areabase.first; sa; sa = sa->next) {
1889                 switch (sa->spacetype) {
1890                         case SPACE_VIEW3D:
1891                         {
1892                                 View3D *v3d;
1893
1894                                 if (!is_multiview)
1895                                         continue;
1896
1897                                 v3d = sa->spacedata.first;
1898                                 if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
1899                                         ARegion *ar;
1900                                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
1901                                                 if (ar->regiondata && ar->regiontype == RGN_TYPE_WINDOW) {
1902                                                         RegionView3D *rv3d = ar->regiondata;
1903                                                         if (rv3d->persp == RV3D_CAMOB) {
1904                                                                 return true;
1905                                                         }
1906                                                 }
1907                                         }
1908                                 }
1909                                 break;
1910                         }
1911                         case SPACE_IMAGE:
1912                         {
1913                                 SpaceImage *sima;
1914
1915                                 /* images should always show in stereo, even if
1916                                  * the file doesn't have views enabled */
1917                                 sima = sa->spacedata.first;
1918                                 if (sima->image && BKE_image_is_stereo(sima->image) &&
1919                                     (sima->iuser.flag & IMA_SHOW_STEREO))
1920                                 {
1921                                         return true;
1922                                 }
1923                                 break;
1924                         }
1925                         case SPACE_NODE:
1926                         {
1927                                 SpaceNode *snode;
1928
1929                                 if (!is_multiview)
1930                                         continue;
1931
1932                                 snode = sa->spacedata.first;
1933                                 if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
1934                                         return true;
1935                                 }
1936                                 break;
1937                         }
1938                         case SPACE_SEQ:
1939                         {
1940                                 SpaceSeq *sseq;
1941
1942                                 if (!is_multiview)
1943                                         continue;
1944
1945                                 sseq = sa->spacedata.first;
1946                                 if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
1947                                         return true;
1948                                 }
1949
1950                                 if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
1951                                         return true;
1952                                 }
1953
1954                                 break;
1955                         }
1956                 }
1957         }
1958
1959         return false;
1960 }