1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2008 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edscr
22 */
23
24 #include <math.h>
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_object_types.h"
30 #include "DNA_scene_types.h"
31 #include "DNA_userdef_types.h"
32 #include "DNA_workspace_types.h"
33
34 #include "BLI_blenlib.h"
35 #include "BLI_utildefines.h"
36
37 #include "BKE_context.h"
38 #include "BKE_global.h"
39 #include "BKE_icons.h"
40 #include "BKE_image.h"
41 #include "BKE_layer.h"
42 #include "BKE_lib_id.h"
43 #include "BKE_main.h"
44 #include "BKE_scene.h"
45 #include "BKE_screen.h"
46 #include "BKE_sound.h"
47 #include "BKE_workspace.h"
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51
52 #include "ED_clip.h"
53 #include "ED_node.h"
54 #include "ED_screen.h"
55 #include "ED_screen_types.h"
56
57 #include "UI_interface.h"
58
59 #include "WM_message.h"
60
61 #include "DEG_depsgraph_query.h"
62
63 #include "screen_intern.h" /* own module include */
64
65 /* adds no space data */
screen_addarea_ex(ScrAreaMap * area_map,ScrVert * bottom_left,ScrVert * top_left,ScrVert * top_right,ScrVert * bottom_right,short spacetype)66 static ScrArea *screen_addarea_ex(ScrAreaMap *area_map,
67 ScrVert *bottom_left,
68 ScrVert *top_left,
69 ScrVert *top_right,
70 ScrVert *bottom_right,
71 short spacetype)
72 {
73 ScrArea *area = MEM_callocN(sizeof(ScrArea), "addscrarea");
74
75 area->v1 = bottom_left;
76 area->v2 = top_left;
77 area->v3 = top_right;
78 area->v4 = bottom_right;
79 area->spacetype = spacetype;
80
81 BLI_addtail(&area_map->areabase, area);
82
83 return area;
84 }
screen_addarea(bScreen * screen,ScrVert * left_bottom,ScrVert * left_top,ScrVert * right_top,ScrVert * right_bottom,short spacetype)85 static ScrArea *screen_addarea(bScreen *screen,
86 ScrVert *left_bottom,
87 ScrVert *left_top,
88 ScrVert *right_top,
89 ScrVert *right_bottom,
90 short spacetype)
91 {
92 return screen_addarea_ex(
93 AREAMAP_FROM_SCREEN(screen), left_bottom, left_top, right_top, right_bottom, spacetype);
94 }
95
screen_delarea(bContext * C,bScreen * screen,ScrArea * area)96 static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
97 {
98
99 ED_area_exit(C, area);
100
101 BKE_screen_area_free(area);
102
103 BLI_remlink(&screen->areabase, area);
104 MEM_freeN(area);
105 }
106
area_split(const wmWindow * win,bScreen * screen,ScrArea * area,char dir,float fac,int merge)107 ScrArea *area_split(
108 const wmWindow *win, bScreen *screen, ScrArea *area, char dir, float fac, int merge)
109 {
110 ScrArea *newa = NULL;
111
112 if (area == NULL) {
113 return NULL;
114 }
115
116 rcti window_rect;
117 WM_window_rect_calc(win, &window_rect);
118
119 short split = screen_geom_find_area_split_point(area, &window_rect, dir, fac);
120 if (split == 0) {
121 return NULL;
122 }
123
124 /* note regarding (fac > 0.5f) checks below.
125 * normally it shouldn't matter which is used since the copy should match the original
126 * however with viewport rendering and python console this isn't the case. - campbell */
127
128 if (dir == 'h') {
129 /* new vertices */
130 ScrVert *sv1 = screen_geom_vertex_add(screen, area->v1->vec.x, split);
131 ScrVert *sv2 = screen_geom_vertex_add(screen, area->v4->vec.x, split);
132
133 /* new edges */
134 screen_geom_edge_add(screen, area->v1, sv1);
135 screen_geom_edge_add(screen, sv1, area->v2);
136 screen_geom_edge_add(screen, area->v3, sv2);
137 screen_geom_edge_add(screen, sv2, area->v4);
138 screen_geom_edge_add(screen, sv1, sv2);
139
140 if (fac > 0.5f) {
141 /* new areas: top */
142 newa = screen_addarea(screen, sv1, area->v2, area->v3, sv2, area->spacetype);
143
144 /* area below */
145 area->v2 = sv1;
146 area->v3 = sv2;
147 }
148 else {
149 /* new areas: bottom */
150 newa = screen_addarea(screen, area->v1, sv1, sv2, area->v4, area->spacetype);
151
152 /* area above */
153 area->v1 = sv1;
154 area->v4 = sv2;
155 }
156
157 ED_area_data_copy(newa, area, true);
158 }
159 else {
160 /* new vertices */
161 ScrVert *sv1 = screen_geom_vertex_add(screen, split, area->v1->vec.y);
162 ScrVert *sv2 = screen_geom_vertex_add(screen, split, area->v2->vec.y);
163
164 /* new edges */
165 screen_geom_edge_add(screen, area->v1, sv1);
166 screen_geom_edge_add(screen, sv1, area->v4);
167 screen_geom_edge_add(screen, area->v2, sv2);
168 screen_geom_edge_add(screen, sv2, area->v3);
169 screen_geom_edge_add(screen, sv1, sv2);
170
171 if (fac > 0.5f) {
172 /* new areas: right */
173 newa = screen_addarea(screen, sv1, sv2, area->v3, area->v4, area->spacetype);
174
175 /* area left */
176 area->v3 = sv2;
177 area->v4 = sv1;
178 }
179 else {
180 /* new areas: left */
181 newa = screen_addarea(screen, area->v1, area->v2, sv2, sv1, area->spacetype);
182
183 /* area right */
184 area->v1 = sv1;
185 area->v2 = sv2;
186 }
187
188 ED_area_data_copy(newa, area, true);
189 }
190
191 /* remove double vertices en edges */
192 if (merge) {
193 BKE_screen_remove_double_scrverts(screen);
194 }
195 BKE_screen_remove_double_scredges(screen);
196 BKE_screen_remove_unused_scredges(screen);
197
198 return newa;
199 }
200
201 /**
202 * Empty screen, with 1 dummy area without spacedata. Uses window size.
203 */
screen_add(Main * bmain,const char * name,const rcti * rect)204 bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
205 {
206 bScreen *screen = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
207 screen->do_refresh = true;
208 screen->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
209
210 ScrVert *sv1 = screen_geom_vertex_add(screen, rect->xmin, rect->ymin);
211 ScrVert *sv2 = screen_geom_vertex_add(screen, rect->xmin, rect->ymax - 1);
212 ScrVert *sv3 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymax - 1);
213 ScrVert *sv4 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymin);
214
215 screen_geom_edge_add(screen, sv1, sv2);
216 screen_geom_edge_add(screen, sv2, sv3);
217 screen_geom_edge_add(screen, sv3, sv4);
218 screen_geom_edge_add(screen, sv4, sv1);
219
220 /* dummy type, no spacedata */
221 screen_addarea(screen, sv1, sv2, sv3, sv4, SPACE_EMPTY);
222
223 return screen;
224 }
225
screen_data_copy(bScreen * to,bScreen * from)226 void screen_data_copy(bScreen *to, bScreen *from)
227 {
228 /* free contents of 'to', is from blenkernel screen.c */
229 BKE_screen_free(to);
230
231 to->flag = from->flag;
232
233 BLI_duplicatelist(&to->vertbase, &from->vertbase);
234 BLI_duplicatelist(&to->edgebase, &from->edgebase);
235 BLI_duplicatelist(&to->areabase, &from->areabase);
236 BLI_listbase_clear(&to->regionbase);
237
238 ScrVert *s2 = to->vertbase.first;
239 for (ScrVert *s1 = from->vertbase.first; s1; s1 = s1->next, s2 = s2->next) {
240 s1->newv = s2;
241 }
242
243 LISTBASE_FOREACH (ScrEdge *, se, &to->edgebase) {
244 se->v1 = se->v1->newv;
245 se->v2 = se->v2->newv;
246 BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
247 }
248
249 ScrArea *from_area = from->areabase.first;
250 LISTBASE_FOREACH (ScrArea *, area, &to->areabase) {
251 area->v1 = area->v1->newv;
252 area->v2 = area->v2->newv;
253 area->v3 = area->v3->newv;
254 area->v4 = area->v4->newv;
255
256 BLI_listbase_clear(&area->spacedata);
257 BLI_listbase_clear(&area->regionbase);
258 BLI_listbase_clear(&area->actionzones);
259 BLI_listbase_clear(&area->handlers);
260
261 ED_area_data_copy(area, from_area, true);
262
263 from_area = from_area->next;
264 }
265
266 /* put at zero (needed?) */
267 LISTBASE_FOREACH (ScrVert *, s1, &from->vertbase) {
268 s1->newv = NULL;
269 }
270 }
271
272 /**
273 * Prepare a newly created screen for initializing it as active screen.
274 */
screen_new_activate_prepare(const wmWindow * win,bScreen * screen_new)275 void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
276 {
277 screen_new->winid = win->winid;
278 screen_new->do_refresh = true;
279 screen_new->do_draw = true;
280 }
281
282 /* with area as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
283 /* -1 = not valid check */
284 /* used with join operator */
area_getorientation(ScrArea * area,ScrArea * sb)285 int area_getorientation(ScrArea *area, ScrArea *sb)
286 {
287 if (area == NULL || sb == NULL) {
288 return -1;
289 }
290
291 ScrVert *saBL = area->v1;
292 ScrVert *saTL = area->v2;
293 ScrVert *saTR = area->v3;
294 ScrVert *saBR = area->v4;
295
296 ScrVert *sbBL = sb->v1;
297 ScrVert *sbTL = sb->v2;
298 ScrVert *sbTR = sb->v3;
299 ScrVert *sbBR = sb->v4;
300
301 if (saBL->vec.x == sbBR->vec.x && saTL->vec.x == sbTR->vec.x) { /* area to right of sb = W */
302 if ((abs(saBL->vec.y - sbBR->vec.y) <= AREAJOINTOLERANCE) &&
303 (abs(saTL->vec.y - sbTR->vec.y) <= AREAJOINTOLERANCE)) {
304 return 0;
305 }
306 }
307 else if (saTL->vec.y == sbBL->vec.y &&
308 saTR->vec.y == sbBR->vec.y) { /* area to bottom of sb = N */
309 if ((abs(saTL->vec.x - sbBL->vec.x) <= AREAJOINTOLERANCE) &&
310 (abs(saTR->vec.x - sbBR->vec.x) <= AREAJOINTOLERANCE)) {
311 return 1;
312 }
313 }
314 else if (saTR->vec.x == sbTL->vec.x && saBR->vec.x == sbBL->vec.x) { /* area to left of sb = E */
315 if ((abs(saTR->vec.y - sbTL->vec.y) <= AREAJOINTOLERANCE) &&
316 (abs(saBR->vec.y - sbBL->vec.y) <= AREAJOINTOLERANCE)) {
317 return 2;
318 }
319 }
320 else if (saBL->vec.y == sbTL->vec.y && saBR->vec.y == sbTR->vec.y) { /* area on top of sb = S*/
321 if ((abs(saBL->vec.x - sbTL->vec.x) <= AREAJOINTOLERANCE) &&
322 (abs(saBR->vec.x - sbTR->vec.x) <= AREAJOINTOLERANCE)) {
323 return 3;
324 }
325 }
326
327 return -1;
328 }
329
330 /* Screen verts with horizontal position equal to from_x are moved to to_x. */
screen_verts_halign(const wmWindow * win,const bScreen * screen,const short from_x,const short to_x)331 static void screen_verts_halign(const wmWindow *win,
332 const bScreen *screen,
333 const short from_x,
334 const short to_x)
335 {
336 ED_screen_verts_iter(win, screen, v1)
337 {
338 if (v1->vec.x == from_x) {
339 v1->vec.x = to_x;
340 }
341 }
342 }
343
344 /* Screen verts with vertical position equal to from_y are moved to to_y. */
screen_verts_valign(const wmWindow * win,const bScreen * screen,const short from_y,const short to_y)345 static void screen_verts_valign(const wmWindow *win,
346 const bScreen *screen,
347 const short from_y,
348 const short to_y)
349 {
350 ED_screen_verts_iter(win, screen, v1)
351 {
352 if (v1->vec.y == from_y) {
353 v1->vec.y = to_y;
354 }
355 }
356 }
357
358 /* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation().
359 */
screen_areas_align(bContext * C,bScreen * screen,ScrArea * sa1,ScrArea * sa2,const int dir)360 static void screen_areas_align(
361 bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const int dir)
362 {
363 wmWindow *win = CTX_wm_window(C);
364
365 if (dir == 0 || dir == 2) {
366 /* horizontal join, use average for new top and bottom. */
367 int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2;
368 int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2;
369
370 /* Move edges exactly matching source top and bottom. */
371 screen_verts_valign(win, screen, sa1->v2->vec.y, top);
372 screen_verts_valign(win, screen, sa1->v4->vec.y, bottom);
373
374 /* Move edges exactly matching target top and bottom. */
375 screen_verts_valign(win, screen, sa2->v2->vec.y, top);
376 screen_verts_valign(win, screen, sa2->v4->vec.y, bottom);
377 }
378 else {
379 /* Vertical join, use averages for new left and right. */
380 int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2;
381 int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2;
382
383 /* Move edges exactly matching source left and right. */
384 screen_verts_halign(win, screen, sa1->v1->vec.x, left);
385 screen_verts_halign(win, screen, sa1->v3->vec.x, right);
386
387 /* Move edges exactly matching target left and right */
388 screen_verts_halign(win, screen, sa2->v1->vec.x, left);
389 screen_verts_halign(win, screen, sa2->v3->vec.x, right);
390 }
391 }
392
393 /* Helper function to join 2 areas, it has a return value, 0=failed 1=success
394 * used by the split, join operators
395 */
screen_area_join(bContext * C,bScreen * screen,ScrArea * sa1,ScrArea * sa2)396 int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
397 {
398 int dir = area_getorientation(sa1, sa2);
399
400 if (dir == -1) {
401 return 0;
402 }
403
404 /* Align areas if they are not. Do sanity checking before getting here. */
405 screen_areas_align(C, screen, sa1, sa2, dir);
406
407 if (dir == 0) { /* sa1 to right of sa2 = W */
408 sa1->v1 = sa2->v1; /* BL */
409 sa1->v2 = sa2->v2; /* TL */
410 screen_geom_edge_add(screen, sa1->v2, sa1->v3);
411 screen_geom_edge_add(screen, sa1->v1, sa1->v4);
412 }
413 else if (dir == 1) { /* sa1 to bottom of sa2 = N */
414 sa1->v2 = sa2->v2; /* TL */
415 sa1->v3 = sa2->v3; /* TR */
416 screen_geom_edge_add(screen, sa1->v1, sa1->v2);
417 screen_geom_edge_add(screen, sa1->v3, sa1->v4);
418 }
419 else if (dir == 2) { /* sa1 to left of sa2 = E */
420 sa1->v3 = sa2->v3; /* TR */
421 sa1->v4 = sa2->v4; /* BR */
422 screen_geom_edge_add(screen, sa1->v2, sa1->v3);
423 screen_geom_edge_add(screen, sa1->v1, sa1->v4);
424 }
425 else if (dir == 3) { /* sa1 on top of sa2 = S */
426 sa1->v1 = sa2->v1; /* BL */
427 sa1->v4 = sa2->v4; /* BR */
428 screen_geom_edge_add(screen, sa1->v1, sa1->v2);
429 screen_geom_edge_add(screen, sa1->v3, sa1->v4);
430 }
431
432 screen_delarea(C, screen, sa2);
433 BKE_screen_remove_double_scrverts(screen);
434 /* Update preview thumbnail */
435 BKE_icon_changed(screen->id.icon_id);
436
437 return 1;
438 }
439
440 /* ****************** EXPORTED API TO OTHER MODULES *************************** */
441
442 /* screen sets cursor based on active region */
region_cursor_set_ex(wmWindow * win,ScrArea * area,ARegion * region,bool swin_changed)443 static void region_cursor_set_ex(wmWindow *win, ScrArea *area, ARegion *region, bool swin_changed)
444 {
445 BLI_assert(WM_window_get_active_screen(win)->active_region == region);
446 if (win->tag_cursor_refresh || swin_changed || (region->type && region->type->event_cursor)) {
447 win->tag_cursor_refresh = false;
448 ED_region_cursor_set(win, area, region);
449 }
450 }
451
region_cursor_set(wmWindow * win,bool swin_changed)452 static void region_cursor_set(wmWindow *win, bool swin_changed)
453 {
454 bScreen *screen = WM_window_get_active_screen(win);
455
456 ED_screen_areas_iter (win, screen, area) {
457 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
458 if (region == screen->active_region) {
459 region_cursor_set_ex(win, area, region, swin_changed);
460 return;
461 }
462 }
463 }
464 }
465
ED_screen_do_listen(bContext * C,wmNotifier * note)466 void ED_screen_do_listen(bContext *C, wmNotifier *note)
467 {
468 wmWindow *win = CTX_wm_window(C);
469 bScreen *screen = CTX_wm_screen(C);
470
471 /* generic notes */
472 switch (note->category) {
473 case NC_WM:
474 if (note->data == ND_FILEREAD) {
475 screen->do_draw = true;
476 }
477 break;
478 case NC_WINDOW:
479 screen->do_draw = true;
480 break;
481 case NC_SCREEN:
482 if (note->action == NA_EDITED) {
483 screen->do_draw = screen->do_refresh = true;
484 }
485 break;
486 case NC_SCENE:
487 if (note->data == ND_MODE) {
488 region_cursor_set(win, true);
489 }
490 break;
491 }
492 }
493
494 /* make this screen usable */
495 /* for file read and first use, for scaling window, area moves */
ED_screen_refresh(wmWindowManager * wm,wmWindow * win)496 void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
497 {
498 bScreen *screen = WM_window_get_active_screen(win);
499
500 /* exception for bg mode, we only need the screen context */
501 if (!G.background) {
502 /* header size depends on DPI, let's verify */
503 WM_window_set_dpi(win);
504
505 ED_screen_global_areas_refresh(win);
506
507 screen_geom_vertices_scale(win, screen);
508
509 ED_screen_areas_iter (win, screen, area) {
510 /* set spacetype and region callbacks, calls init() */
511 /* sets subwindows for regions, adds handlers */
512 ED_area_init(wm, win, area);
513 }
514
515 /* wake up animtimer */
516 if (screen->animtimer) {
517 WM_event_timer_sleep(wm, win, screen->animtimer, false);
518 }
519 }
520
521 if (G.debug & G_DEBUG_EVENTS) {
522 printf("%s: set screen\n", __func__);
523 }
524 screen->do_refresh = false;
525 /* prevent multiwin errors */
526 screen->winid = win->winid;
527
528 screen->context = ed_screen_context;
529 }
530
531 /* file read, set all screens, ... */
ED_screens_init(Main * bmain,wmWindowManager * wm)532 void ED_screens_init(Main *bmain, wmWindowManager *wm)
533 {
534 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
535 if (BKE_workspace_active_get(win->workspace_hook) == NULL) {
536 BKE_workspace_active_set(win->workspace_hook, bmain->workspaces.first);
537 }
538
539 ED_screen_refresh(wm, win);
540 if (win->eventstate) {
541 ED_screen_set_active_region(NULL, win, &win->eventstate->x);
542 }
543 }
544
545 if (U.uiflag & USER_HEADER_FROM_PREF) {
546 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
547 BKE_screen_header_alignment_reset(screen);
548 }
549 }
550 }
551
ED_screen_ensure_updated(wmWindowManager * wm,wmWindow * win,bScreen * screen)552 void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *screen)
553 {
554 if (screen->do_refresh) {
555 ED_screen_refresh(wm, win);
556 }
557 }
558
559 /**
560 * Utility to exit and free an area-region. Screen level regions (menus/popups) need to be treated
561 * slightly differently, see #ui_region_temp_remove().
562 */
ED_region_remove(bContext * C,ScrArea * area,ARegion * region)563 void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
564 {
565 ED_region_exit(C, region);
566 BKE_area_region_free(area->type, region);
567 BLI_freelinkN(&area->regionbase, region);
568 }
569
570 /* *********** exit calls are for closing running stuff ******** */
571
ED_region_exit(bContext * C,ARegion * region)572 void ED_region_exit(bContext *C, ARegion *region)
573 {
574 wmWindowManager *wm = CTX_wm_manager(C);
575 wmWindow *win = CTX_wm_window(C);
576 ARegion *prevar = CTX_wm_region(C);
577
578 if (region->type && region->type->exit) {
579 region->type->exit(wm, region);
580 }
581
582 CTX_wm_region_set(C, region);
583
584 WM_event_remove_handlers(C, ®ion->handlers);
585 WM_event_modal_handler_region_replace(win, region, NULL);
586 WM_draw_region_free(region, true);
587
588 if (region->headerstr) {
589 MEM_freeN(region->headerstr);
590 region->headerstr = NULL;
591 }
592
593 if (region->regiontimer) {
594 WM_event_remove_timer(wm, win, region->regiontimer);
595 region->regiontimer = NULL;
596 }
597
598 WM_msgbus_clear_by_owner(wm->message_bus, region);
599
600 CTX_wm_region_set(C, prevar);
601 }
602
ED_area_exit(bContext * C,ScrArea * area)603 void ED_area_exit(bContext *C, ScrArea *area)
604 {
605 wmWindowManager *wm = CTX_wm_manager(C);
606 wmWindow *win = CTX_wm_window(C);
607 ScrArea *prevsa = CTX_wm_area(C);
608
609 if (area->type && area->type->exit) {
610 area->type->exit(wm, area);
611 }
612
613 CTX_wm_area_set(C, area);
614
615 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
616 ED_region_exit(C, region);
617 }
618
619 WM_event_remove_handlers(C, &area->handlers);
620 WM_event_modal_handler_area_replace(win, area, NULL);
621
622 CTX_wm_area_set(C, prevsa);
623 }
624
ED_screen_exit(bContext * C,wmWindow * window,bScreen * screen)625 void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
626 {
627 wmWindowManager *wm = CTX_wm_manager(C);
628 wmWindow *prevwin = CTX_wm_window(C);
629
630 CTX_wm_window_set(C, window);
631
632 if (screen->animtimer) {
633 WM_event_remove_timer(wm, window, screen->animtimer);
634
635 Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
636 Scene *scene = WM_window_get_active_scene(prevwin);
637 Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
638 BKE_sound_stop_scene(scene_eval);
639 }
640 screen->animtimer = NULL;
641 screen->scrubbing = false;
642
643 screen->active_region = NULL;
644
645 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
646 ED_region_exit(C, region);
647 }
648 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
649 ED_area_exit(C, area);
650 }
651 /* Don't use ED_screen_areas_iter here, it skips hidden areas. */
652 LISTBASE_FOREACH (ScrArea *, area, &window->global_areas.areabase) {
653 ED_area_exit(C, area);
654 }
655
656 /* mark it available for use for other windows */
657 screen->winid = 0;
658
659 if (!WM_window_is_temp_screen(prevwin)) {
660 /* use previous window if possible */
661 CTX_wm_window_set(C, prevwin);
662 }
663 else {
664 /* none otherwise */
665 CTX_wm_window_set(C, NULL);
666 }
667 }
668
669 /* *********************************** */
670
671 /* case when on area-edge or in azones, or outside window */
screen_cursor_set(wmWindow * win,const int xy[2])672 static void screen_cursor_set(wmWindow *win, const int xy[2])
673 {
674 const bScreen *screen = WM_window_get_active_screen(win);
675 AZone *az = NULL;
676 ScrArea *area = NULL;
677
678 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
679 if ((az = ED_area_actionzone_find_xy(area_iter, xy))) {
680 area = area_iter;
681 break;
682 }
683 }
684
685 if (area) {
686 if (az->type == AZONE_AREA) {
687 WM_cursor_set(win, WM_CURSOR_EDIT);
688 }
689 else if (az->type == AZONE_REGION) {
690 if (az->edge == AE_LEFT_TO_TOPRIGHT || az->edge == AE_RIGHT_TO_TOPLEFT) {
691 WM_cursor_set(win, WM_CURSOR_X_MOVE);
692 }
693 else {
694 WM_cursor_set(win, WM_CURSOR_Y_MOVE);
695 }
696 }
697 }
698 else {
699 ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, xy[0], xy[1]);
700
701 if (actedge) {
702 if (screen_geom_edge_is_horizontal(actedge)) {
703 WM_cursor_set(win, WM_CURSOR_Y_MOVE);
704 }
705 else {
706 WM_cursor_set(win, WM_CURSOR_X_MOVE);
707 }
708 }
709 else {
710 WM_cursor_set(win, WM_CURSOR_DEFAULT);
711 }
712 }
713 }
714
715 /**
716 * Called in wm_event_system.c. sets state vars in screen, cursors.
717 * event type is mouse move.
718 */
ED_screen_set_active_region(bContext * C,wmWindow * win,const int xy[2])719 void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
720 {
721 bScreen *screen = WM_window_get_active_screen(win);
722 if (screen == NULL) {
723 return;
724 }
725
726 ScrArea *area = NULL;
727 ARegion *region_prev = screen->active_region;
728
729 ED_screen_areas_iter (win, screen, area_iter) {
730 if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) &&
731 xy[0] < (area_iter->totrct.xmax - BORDERPADDING)) {
732 if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) &&
733 xy[1] < (area_iter->totrct.ymax - BORDERPADDING)) {
734 if (ED_area_azones_update(area_iter, xy) == NULL) {
735 area = area_iter;
736 break;
737 }
738 }
739 }
740 }
741 if (area) {
742 /* Make overlap active when mouse over. */
743 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
744 if (ED_region_contains_xy(region, xy)) {
745 screen->active_region = region;
746 break;
747 }
748 }
749 }
750 else {
751 screen->active_region = NULL;
752 }
753
754 /* Check for redraw headers. */
755 if (region_prev != screen->active_region) {
756
757 ED_screen_areas_iter (win, screen, area_iter) {
758 bool do_draw = false;
759
760 LISTBASE_FOREACH (ARegion *, region, &area_iter->regionbase) {
761 /* Call old area's deactivate if assigned. */
762 if (region == region_prev && area_iter->type->deactivate) {
763 area_iter->type->deactivate(area_iter);
764 }
765
766 if (region == region_prev && region != screen->active_region) {
767 wmGizmoMap *gzmap = region_prev->gizmo_map;
768 if (gzmap) {
769 if (WM_gizmo_highlight_set(gzmap, NULL)) {
770 ED_region_tag_redraw_no_rebuild(region_prev);
771 }
772 }
773 }
774
775 if (region == region_prev || region == screen->active_region) {
776 do_draw = true;
777 }
778 }
779
780 if (do_draw) {
781 LISTBASE_FOREACH (ARegion *, region, &area_iter->regionbase) {
782 if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
783 ED_region_tag_redraw_no_rebuild(region);
784 }
785 }
786 }
787 }
788 }
789
790 /* Cursors, for time being set always on edges,
791 * otherwise the active region doesn't switch. */
792 if (screen->active_region == NULL) {
793 screen_cursor_set(win, xy);
794 }
795 else {
796 /* Notifier invokes freeing the buttons... causing a bit too much redraws. */
797 region_cursor_set_ex(win, area, screen->active_region, region_prev != screen->active_region);
798
799 if (region_prev != screen->active_region) {
800 /* This used to be a notifier, but needs to be done immediate
801 * because it can undo setting the right button as active due
802 * to delayed notifier handling. */
803 if (C) {
804 UI_screen_free_active_but(C, screen);
805 }
806 }
807 }
808 }
809
ED_screen_area_active(const bContext * C)810 int ED_screen_area_active(const bContext *C)
811 {
812 wmWindow *win = CTX_wm_window(C);
813 bScreen *screen = CTX_wm_screen(C);
814 ScrArea *area = CTX_wm_area(C);
815
816 if (win && screen && area) {
817 AZone *az = ED_area_actionzone_find_xy(area, &win->eventstate->x);
818
819 if (az && az->type == AZONE_REGION) {
820 return 1;
821 }
822
823 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
824 if (region == screen->active_region) {
825 return 1;
826 }
827 }
828 }
829 return 0;
830 }
831
832 /**
833 * Add an area and geometry (screen-edges and -vertices) for it to \a area_map,
834 * with coordinates/dimensions matching \a rect.
835 */
screen_area_create_with_geometry(ScrAreaMap * area_map,const rcti * rect,short spacetype)836 static ScrArea *screen_area_create_with_geometry(ScrAreaMap *area_map,
837 const rcti *rect,
838 short spacetype)
839 {
840 ScrVert *bottom_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin);
841 ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax);
842 ScrVert *top_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymax);
843 ScrVert *bottom_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymin);
844
845 screen_geom_edge_add_ex(area_map, bottom_left, top_left);
846 screen_geom_edge_add_ex(area_map, top_left, top_right);
847 screen_geom_edge_add_ex(area_map, top_right, bottom_right);
848 screen_geom_edge_add_ex(area_map, bottom_right, bottom_left);
849
850 return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
851 }
852
screen_area_set_geometry_rect(ScrArea * area,const rcti * rect)853 static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
854 {
855 area->v1->vec.x = rect->xmin;
856 area->v1->vec.y = rect->ymin;
857 area->v2->vec.x = rect->xmin;
858 area->v2->vec.y = rect->ymax;
859 area->v3->vec.x = rect->xmax;
860 area->v3->vec.y = rect->ymax;
861 area->v4->vec.x = rect->xmax;
862 area->v4->vec.y = rect->ymin;
863 }
864
screen_global_area_refresh(wmWindow * win,bScreen * screen,eSpace_Type space_type,GlobalAreaAlign align,const rcti * rect,const short height_cur,const short height_min,const short height_max)865 static void screen_global_area_refresh(wmWindow *win,
866 bScreen *screen,
867 eSpace_Type space_type,
868 GlobalAreaAlign align,
869 const rcti *rect,
870 const short height_cur,
871 const short height_min,
872 const short height_max)
873 {
874 ScrArea *area = NULL;
875 LISTBASE_FOREACH (ScrArea *, area_iter, &win->global_areas.areabase) {
876 if (area_iter->spacetype == space_type) {
877 area = area_iter;
878 break;
879 }
880 }
881
882 if (area) {
883 screen_area_set_geometry_rect(area, rect);
884 }
885 else {
886 area = screen_area_create_with_geometry(&win->global_areas, rect, space_type);
887 SpaceType *stype = BKE_spacetype_from_id(space_type);
888 SpaceLink *slink = stype->create(area, WM_window_get_active_scene(win));
889
890 area->regionbase = slink->regionbase;
891
892 BLI_addhead(&area->spacedata, slink);
893 BLI_listbase_clear(&slink->regionbase);
894
895 /* Data specific to global areas. */
896 area->global = MEM_callocN(sizeof(*area->global), __func__);
897 area->global->size_max = height_max;
898 area->global->size_min = height_min;
899 area->global->align = align;
900 }
901
902 if (area->global->cur_fixed_height != height_cur) {
903 /* Refresh layout if size changes. */
904 area->global->cur_fixed_height = height_cur;
905 screen->do_refresh = true;
906 }
907 }
908
screen_global_header_size(void)909 static int screen_global_header_size(void)
910 {
911 return (int)ceilf(ED_area_headersize() / UI_DPI_FAC);
912 }
913
screen_global_topbar_area_refresh(wmWindow * win,bScreen * screen)914 static void screen_global_topbar_area_refresh(wmWindow *win, bScreen *screen)
915 {
916 const short size = screen_global_header_size();
917 rcti rect;
918
919 BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1);
920 rect.ymin = rect.ymax - size;
921
922 screen_global_area_refresh(
923 win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size, size);
924 }
925
screen_global_statusbar_area_refresh(wmWindow * win,bScreen * screen)926 static void screen_global_statusbar_area_refresh(wmWindow *win, bScreen *screen)
927 {
928 const short size_min = 1;
929 const short size_max = 0.8f * screen_global_header_size();
930 const short size = (screen->flag & SCREEN_COLLAPSE_STATUSBAR) ? size_min : size_max;
931 rcti rect;
932
933 BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1);
934 rect.ymax = rect.ymin + size_max;
935
936 screen_global_area_refresh(
937 win, screen, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size, size_min, size_max);
938 }
939
ED_screen_global_areas_sync(wmWindow * win)940 void ED_screen_global_areas_sync(wmWindow *win)
941 {
942 /* Update screen flags from height in window, this is weak and perhaps
943 * global areas should just become part of the screen instead. */
944 bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
945
946 screen->flag &= ~SCREEN_COLLAPSE_STATUSBAR;
947
948 LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) {
949 if (area->global->cur_fixed_height == area->global->size_min) {
950 if (area->spacetype == SPACE_STATUSBAR) {
951 screen->flag |= SCREEN_COLLAPSE_STATUSBAR;
952 }
953 }
954 }
955 }
956
ED_screen_global_areas_refresh(wmWindow * win)957 void ED_screen_global_areas_refresh(wmWindow *win)
958 {
959 /* Don't create global area for child and temporary windows. */
960 bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
961 if ((win->parent != NULL) || screen->temp) {
962 if (win->global_areas.areabase.first) {
963 screen->do_refresh = true;
964 BKE_screen_area_map_free(&win->global_areas);
965 }
966 return;
967 }
968
969 screen_global_topbar_area_refresh(win, screen);
970 screen_global_statusbar_area_refresh(win, screen);
971 }
972
973 /* -------------------------------------------------------------------- */
974 /* Screen changing */
975
976 /**
977 * \return the screen to activate.
978 * \warning The returned screen may not always equal \a screen_new!
979 */
screen_change_prepare(bScreen * screen_old,bScreen * screen_new,Main * bmain,bContext * C,wmWindow * win)980 void screen_change_prepare(
981 bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
982 {
983 UNUSED_VARS_NDEBUG(bmain);
984 BLI_assert(BLI_findindex(&bmain->screens, screen_new) != -1);
985
986 if (screen_old != screen_new) {
987 wmTimer *wt = screen_old->animtimer;
988
989 /* remove handlers referencing areas in old screen */
990 LISTBASE_FOREACH (ScrArea *, area, &screen_old->areabase) {
991 WM_event_remove_area_handler(&win->modalhandlers, area);
992 }
993
994 /* we put timer to sleep, so screen_exit has to think there's no timer */
995 screen_old->animtimer = NULL;
996 if (wt) {
997 WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
998 }
999 ED_screen_exit(C, win, screen_old);
1000
1001 /* Same scene, "transfer" playback to new screen. */
1002 if (wt) {
1003 screen_new->animtimer = wt;
1004 }
1005 }
1006 }
1007
screen_change_update(bContext * C,wmWindow * win,bScreen * screen)1008 void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
1009 {
1010 Scene *scene = WM_window_get_active_scene(win);
1011 WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
1012 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
1013
1014 CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
1015
1016 ED_screen_refresh(CTX_wm_manager(C), win);
1017
1018 BKE_screen_view3d_scene_sync(screen, scene); /* sync new screen with scene data */
1019 WM_event_add_notifier(C, NC_WINDOW, NULL);
1020 WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout);
1021
1022 /* makes button hilites work */
1023 WM_event_add_mousemove(win);
1024 }
1025
1026 /**
1027 * \brief Change the active screen.
1028 *
1029 * Operator call, WM + Window + screen already existed before
1030 *
1031 * \warning Do NOT call in area/region queues!
1032 * \returns if screen changing was successful.
1033 */
ED_screen_change(bContext * C,bScreen * screen)1034 bool ED_screen_change(bContext *C, bScreen *screen)
1035 {
1036 Main *bmain = CTX_data_main(C);
1037 wmWindow *win = CTX_wm_window(C);
1038 WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
1039 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
1040 bScreen *screen_old = CTX_wm_screen(C);
1041
1042 /* Get the actual layout/screen to be activated (guaranteed to be unused, even if that means
1043 * having to duplicate an existing one). */
1044 WorkSpaceLayout *layout_new = ED_workspace_screen_change_ensure_unused_layout(
1045 bmain, workspace, layout, layout, win);
1046 bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
1047
1048 screen_change_prepare(screen_old, screen_new, bmain, C, win);
1049
1050 if (screen_old != screen_new) {
1051 WM_window_set_active_screen(win, workspace, screen_new);
1052 screen_change_update(C, win, screen_new);
1053
1054 return true;
1055 }
1056
1057 return false;
1058 }
1059
screen_set_3dview_camera(Scene * scene,ViewLayer * view_layer,ScrArea * area,View3D * v3d)1060 static void screen_set_3dview_camera(Scene *scene,
1061 ViewLayer *view_layer,
1062 ScrArea *area,
1063 View3D *v3d)
1064 {
1065 /* fix any cameras that are used in the 3d view but not in the scene */
1066 BKE_screen_view3d_sync(v3d, scene);
1067
1068 if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
1069 v3d->camera = BKE_view_layer_camera_find(view_layer);
1070 // XXX if (screen == curscreen) handle_view3d_lock();
1071 if (!v3d->camera) {
1072 ListBase *regionbase;
1073
1074 /* regionbase is in different place depending if space is active */
1075 if (v3d == area->spacedata.first) {
1076 regionbase = &area->regionbase;
1077 }
1078 else {
1079 regionbase = &v3d->regionbase;
1080 }
1081
1082 LISTBASE_FOREACH (ARegion *, region, regionbase) {
1083 if (region->regiontype == RGN_TYPE_WINDOW) {
1084 RegionView3D *rv3d = region->regiondata;
1085 if (rv3d->persp == RV3D_CAMOB) {
1086 rv3d->persp = RV3D_PERSP;
1087 }
1088 }
1089 }
1090 }
1091 }
1092 }
1093
ED_screen_scene_change(bContext * C,wmWindow * win,Scene * scene)1094 void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene)
1095 {
1096 #if 0
1097 ViewLayer *view_layer_old = WM_window_get_active_view_layer(win);
1098 #endif
1099
1100 /* Switch scene. */
1101 win->scene = scene;
1102 if (CTX_wm_window(C) == win) {
1103 CTX_data_scene_set(C, scene);
1104 }
1105
1106 /* Ensure the view layer name is updated. */
1107 WM_window_ensure_active_view_layer(win);
1108 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
1109
1110 #if 0
1111 /* Mode Syncing. */
1112 if (view_layer_old) {
1113 WorkSpace *workspace = CTX_wm_workspace(C);
1114 Object *obact_new = OBACT(view_layer);
1115 UNUSED_VARS(obact_new);
1116 eObjectMode object_mode_old = workspace->object_mode;
1117 Object *obact_old = OBACT(view_layer_old);
1118 UNUSED_VARS(obact_old, object_mode_old);
1119 }
1120 #endif
1121
1122 /* Update 3D view cameras. */
1123 const bScreen *screen = WM_window_get_active_screen(win);
1124 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1125 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
1126 if (sl->spacetype == SPACE_VIEW3D) {
1127 View3D *v3d = (View3D *)sl;
1128 screen_set_3dview_camera(scene, view_layer, area, v3d);
1129 }
1130 }
1131 }
1132 }
1133
ED_screen_full_newspace(bContext * C,ScrArea * area,int type)1134 ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
1135 {
1136 wmWindow *win = CTX_wm_window(C);
1137 ScrArea *newsa = NULL;
1138 SpaceLink *newsl;
1139
1140 if (!area || area->full == NULL) {
1141 newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
1142 }
1143
1144 if (!newsa) {
1145 newsa = area;
1146 }
1147
1148 BLI_assert(newsa);
1149 newsl = newsa->spacedata.first;
1150
1151 /* Tag the active space before changing, so we can identify it when user wants to go back. */
1152 if ((newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) {
1153 newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE;
1154 }
1155
1156 ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY);
1157
1158 return newsa;
1159 }
1160
1161 /**
1162 * \a was_prev_temp for the case previous space was a temporary fullscreen as well
1163 */
ED_screen_full_prevspace(bContext * C,ScrArea * area)1164 void ED_screen_full_prevspace(bContext *C, ScrArea *area)
1165 {
1166 BLI_assert(area->full);
1167
1168 if (area->flag & AREA_FLAG_STACKED_FULLSCREEN) {
1169 /* stacked fullscreen -> only go back to previous area and don't toggle out of fullscreen */
1170 ED_area_prevspace(C, area);
1171 }
1172 else {
1173 ED_screen_restore_temp_type(C, area);
1174 }
1175 }
1176
ED_screen_restore_temp_type(bContext * C,ScrArea * area)1177 void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
1178 {
1179 SpaceLink *sl = area->spacedata.first;
1180
1181 /* In case nether functions below run. */
1182 ED_area_tag_redraw(area);
1183
1184 if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
1185 ED_area_prevspace(C, area);
1186 }
1187
1188 if (area->full) {
1189 ED_screen_state_toggle(C, CTX_wm_window(C), area, SCREENMAXIMIZED);
1190 }
1191 }
1192
1193 /* restore a screen / area back to default operation, after temp fullscreen modes */
ED_screen_full_restore(bContext * C,ScrArea * area)1194 void ED_screen_full_restore(bContext *C, ScrArea *area)
1195 {
1196 wmWindow *win = CTX_wm_window(C);
1197 SpaceLink *sl = area->spacedata.first;
1198 bScreen *screen = CTX_wm_screen(C);
1199 short state = (screen ? screen->state : SCREENMAXIMIZED);
1200
1201 /* if fullscreen area has a temporary space (such as a file browser or fullscreen render
1202 * overlaid on top of an existing setup) then return to the previous space */
1203
1204 if (sl->next) {
1205 if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
1206 ED_screen_full_prevspace(C, area);
1207 }
1208 else {
1209 ED_screen_state_toggle(C, win, area, state);
1210 }
1211 /* warning: 'area' may be freed */
1212 }
1213 /* otherwise just tile the area again */
1214 else {
1215 ED_screen_state_toggle(C, win, area, state);
1216 }
1217 }
1218
1219 /**
1220 * this function toggles: if area is maximized/full then the parent will be restored
1221 *
1222 * \warning \a area may be freed.
1223 */
ED_screen_state_toggle(bContext * C,wmWindow * win,ScrArea * area,const short state)1224 ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
1225 {
1226 Main *bmain = CTX_data_main(C);
1227 wmWindowManager *wm = CTX_wm_manager(C);
1228 WorkSpace *workspace = WM_window_get_active_workspace(win);
1229
1230 if (area) {
1231 /* ensure we don't have a button active anymore, can crash when
1232 * switching screens with tooltip open because region and tooltip
1233 * are no longer in the same screen */
1234 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1235 UI_blocklist_free(C, ®ion->uiblocks);
1236
1237 if (region->regiontimer) {
1238 WM_event_remove_timer(wm, NULL, region->regiontimer);
1239 region->regiontimer = NULL;
1240 }
1241 }
1242
1243 /* prevent hanging status prints */
1244 ED_area_status_text(area, NULL);
1245 ED_workspace_status_text(C, NULL);
1246 }
1247 bScreen *screen;
1248 if (area && area->full) {
1249 WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
1250 /* restoring back to SCREENNORMAL */
1251 screen = area->full; /* the old screen to restore */
1252 bScreen *oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
1253
1254 BLI_assert(BKE_workspace_layout_screen_get(layout_old) != screen);
1255 BLI_assert(BKE_workspace_layout_screen_get(layout_old)->state != SCREENNORMAL);
1256
1257 screen->state = SCREENNORMAL;
1258 screen->flag = oldscreen->flag;
1259
1260 /* find old area to restore from */
1261 ScrArea *fullsa = NULL;
1262 LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) {
1263 /* area to restore from is always first */
1264 if (old->full && !fullsa) {
1265 fullsa = old;
1266 }
1267
1268 /* clear full screen state */
1269 old->full = NULL;
1270 }
1271
1272 area->full = NULL;
1273
1274 if (fullsa == NULL) {
1275 if (G.debug & G_DEBUG) {
1276 printf("%s: something wrong in areafullscreen\n", __func__);
1277 }
1278 return NULL;
1279 }
1280
1281 if (state == SCREENFULL) {
1282 /* unhide global areas */
1283 LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
1284 glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
1285 }
1286 /* restore the old side panels/header visibility */
1287 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1288 region->flag = region->flagfullscreen;
1289 }
1290 }
1291
1292 ED_area_data_swap(fullsa, area);
1293
1294 /* animtimer back */
1295 screen->animtimer = oldscreen->animtimer;
1296 oldscreen->animtimer = NULL;
1297
1298 ED_screen_change(C, screen);
1299 ED_area_tag_refresh(fullsa);
1300
1301 BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
1302
1303 /* After we've restored back to SCREENNORMAL, we have to wait with
1304 * screen handling as it uses the area coords which aren't updated yet.
1305 * Without doing so, the screen handling gets wrong area coords,
1306 * which in worst case can lead to crashes (see T43139) */
1307 screen->skip_handling = true;
1308 }
1309 else {
1310 /* change from SCREENNORMAL to new state */
1311 WorkSpaceLayout *layout_new;
1312 ScrArea *newa;
1313 char newname[MAX_ID_NAME - 2];
1314
1315 BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL));
1316
1317 bScreen *oldscreen = WM_window_get_active_screen(win);
1318
1319 oldscreen->state = state;
1320 BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
1321
1322 layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
1323
1324 screen = BKE_workspace_layout_screen_get(layout_new);
1325 screen->state = state;
1326 screen->redraws_flag = oldscreen->redraws_flag;
1327 screen->temp = oldscreen->temp;
1328 screen->flag = oldscreen->flag;
1329
1330 /* timer */
1331 screen->animtimer = oldscreen->animtimer;
1332 oldscreen->animtimer = NULL;
1333
1334 /* use random area when we have no active one, e.g. when the
1335 * mouse is outside of the window and we open a file browser */
1336 if (!area || area->global) {
1337 area = oldscreen->areabase.first;
1338 }
1339
1340 newa = (ScrArea *)screen->areabase.first;
1341
1342 /* copy area */
1343 ED_area_data_swap(newa, area);
1344 newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
1345
1346 if (state == SCREENFULL) {
1347 /* temporarily hide global areas */
1348 LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
1349 glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
1350 }
1351 /* temporarily hide the side panels/header */
1352 LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) {
1353 region->flagfullscreen = region->flag;
1354
1355 if (ELEM(region->regiontype,
1356 RGN_TYPE_UI,
1357 RGN_TYPE_HEADER,
1358 RGN_TYPE_TOOL_HEADER,
1359 RGN_TYPE_FOOTER,
1360 RGN_TYPE_TOOLS,
1361 RGN_TYPE_NAV_BAR,
1362 RGN_TYPE_EXECUTE)) {
1363 region->flag |= RGN_FLAG_HIDDEN;
1364 }
1365 }
1366 }
1367
1368 area->full = oldscreen;
1369 newa->full = oldscreen;
1370
1371 ED_screen_change(C, screen);
1372 }
1373
1374 /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
1375 CTX_wm_area_set(C, screen->areabase.first);
1376
1377 return screen->areabase.first;
1378 }
1379
1380 /**
1381 * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined
1382 * by \a display_type.
1383 *
1384 * \param title: Title to set for the window, if a window is spawned.
1385 * \param x, y: Position of the window, if a window is spawned.
1386 * \param sizex, sizey: Dimensions of the window, if a window is spawned.
1387 */
ED_screen_temp_space_open(bContext * C,const char * title,int x,int y,int sizex,int sizey,eSpace_Type space_type,int display_type,bool dialog)1388 ScrArea *ED_screen_temp_space_open(bContext *C,
1389 const char *title,
1390 int x,
1391 int y,
1392 int sizex,
1393 int sizey,
1394 eSpace_Type space_type,
1395 int display_type,
1396 bool dialog)
1397 {
1398 ScrArea *area = NULL;
1399
1400 switch (display_type) {
1401 case USER_TEMP_SPACE_DISPLAY_WINDOW:
1402 if (WM_window_open_temp(C, title, x, y, sizex, sizey, (int)space_type, dialog)) {
1403 area = CTX_wm_area(C);
1404 }
1405 break;
1406 case USER_TEMP_SPACE_DISPLAY_FULLSCREEN: {
1407 ScrArea *ctx_area = CTX_wm_area(C);
1408
1409 if (ctx_area != NULL && ctx_area->full) {
1410 area = ctx_area;
1411 ED_area_newspace(C, ctx_area, space_type, true);
1412 area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
1413 ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
1414 }
1415 else if (ctx_area != NULL && ctx_area->spacetype == space_type) {
1416 area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED);
1417 }
1418 else {
1419 area = ED_screen_full_newspace(C, ctx_area, (int)space_type);
1420 ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
1421 }
1422 break;
1423 }
1424 }
1425
1426 return area;
1427 }
1428
1429 /* update frame rate info for viewport drawing */
ED_refresh_viewport_fps(bContext * C)1430 void ED_refresh_viewport_fps(bContext *C)
1431 {
1432 wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
1433 Scene *scene = CTX_data_scene(C);
1434
1435 /* is anim playback running? */
1436 if (animtimer && (U.uiflag & USER_SHOW_FPS)) {
1437 ScreenFrameRateInfo *fpsi = scene->fps_info;
1438
1439 /* if there isn't any info, init it first */
1440 if (fpsi == NULL) {
1441 fpsi = scene->fps_info = MEM_callocN(sizeof(ScreenFrameRateInfo),
1442 "refresh_viewport_fps fps_info");
1443 }
1444
1445 /* update the values */
1446 fpsi->redrawtime = fpsi->lredrawtime;
1447 fpsi->lredrawtime = animtimer->ltime;
1448 }
1449 else {
1450 /* playback stopped or shouldn't be running */
1451 if (scene->fps_info) {
1452 MEM_freeN(scene->fps_info);
1453 }
1454 scene->fps_info = NULL;
1455 }
1456 }
1457
1458 /* redraws: uses defines from stime->redraws
1459 * enable: 1 - forward on, -1 - backwards on, 0 - off
1460 */
ED_screen_animation_timer(bContext * C,int redraws,int sync,int enable)1461 void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
1462 {
1463 bScreen *screen = CTX_wm_screen(C);
1464 wmWindowManager *wm = CTX_wm_manager(C);
1465 wmWindow *win = CTX_wm_window(C);
1466 Scene *scene = CTX_data_scene(C);
1467 bScreen *stopscreen = ED_screen_animation_playing(wm);
1468
1469 if (stopscreen) {
1470 WM_event_remove_timer(wm, win, stopscreen->animtimer);
1471 stopscreen->animtimer = NULL;
1472 }
1473
1474 if (enable) {
1475 ScreenAnimData *sad = MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData");
1476
1477 screen->animtimer = WM_event_add_timer(wm, win, TIMER0, (1.0 / FPS));
1478
1479 sad->region = CTX_wm_region(C);
1480 /* If start-frame is larger than current frame, we put current-frame on start-frame.
1481 * note: first frame then is not drawn! (ton) */
1482 if (PRVRANGEON) {
1483 if (scene->r.psfra > scene->r.cfra) {
1484 sad->sfra = scene->r.cfra;
1485 scene->r.cfra = scene->r.psfra;
1486 }
1487 else {
1488 sad->sfra = scene->r.cfra;
1489 }
1490 }
1491 else {
1492 if (scene->r.sfra > scene->r.cfra) {
1493 sad->sfra = scene->r.cfra;
1494 scene->r.cfra = scene->r.sfra;
1495 }
1496 else {
1497 sad->sfra = scene->r.cfra;
1498 }
1499 }
1500 sad->redraws = redraws;
1501 sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
1502 sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
1503
1504 ScrArea *area = CTX_wm_area(C);
1505
1506 char spacetype = -1;
1507
1508 if (area) {
1509 spacetype = area->spacetype;
1510 }
1511
1512 sad->from_anim_edit = (ELEM(spacetype, SPACE_GRAPH, SPACE_ACTION, SPACE_NLA));
1513
1514 screen->animtimer->customdata = sad;
1515 }
1516
1517 /* Seek audio to ensure playback in preview range with AV sync. */
1518 DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
1519
1520 /* notifier catched by top header, for button */
1521 WM_event_add_notifier(C, NC_SCREEN | ND_ANIMPLAY, NULL);
1522 }
1523
1524 /* helper for screen_animation_play() - only to be used for TimeLine */
time_top_left_3dwindow(bScreen * screen)1525 static ARegion *time_top_left_3dwindow(bScreen *screen)
1526 {
1527 ARegion *aret = NULL;
1528 int min = 10000;
1529
1530 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1531 if (area->spacetype == SPACE_VIEW3D) {
1532 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1533 if (region->regiontype == RGN_TYPE_WINDOW) {
1534 if (region->winrct.xmin - region->winrct.ymin < min) {
1535 aret = region;
1536 min = region->winrct.xmin - region->winrct.ymin;
1537 }
1538 }
1539 }
1540 }
1541 }
1542
1543 return aret;
1544 }
1545
ED_screen_animation_timer_update(bScreen * screen,int redraws)1546 void ED_screen_animation_timer_update(bScreen *screen, int redraws)
1547 {
1548 if (screen && screen->animtimer) {
1549 wmTimer *wt = screen->animtimer;
1550 ScreenAnimData *sad = wt->customdata;
1551
1552 sad->redraws = redraws;
1553 sad->region = NULL;
1554 if (redraws & TIME_REGION) {
1555 sad->region = time_top_left_3dwindow(screen);
1556 }
1557 }
1558 }
1559
1560 /* results in fully updated anim system */
ED_update_for_newframe(Main * bmain,Depsgraph * depsgraph)1561 void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
1562 {
1563 Scene *scene = DEG_get_input_scene(depsgraph);
1564
1565 DEG_time_tag_update(bmain);
1566
1567 #ifdef DURIAN_CAMERA_SWITCH
1568 void *camera = BKE_scene_camera_switch_find(scene);
1569 if (camera && scene->camera != camera) {
1570 scene->camera = camera;
1571 /* are there cameras in the views that are not in the scene? */
1572 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
1573 BKE_screen_view3d_scene_sync(screen, scene);
1574 }
1575 DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
1576 }
1577 #endif
1578
1579 ED_clip_update_frame(bmain, scene->r.cfra);
1580
1581 /* this function applies the changes too */
1582 BKE_scene_graph_update_for_newframe(depsgraph);
1583 }
1584
1585 /*
1586 * return true if any active area requires to see in 3D
1587 */
ED_screen_stereo3d_required(const bScreen * screen,const Scene * scene)1588 bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
1589 {
1590 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
1591
1592 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1593 switch (area->spacetype) {
1594 case SPACE_VIEW3D: {
1595 View3D *v3d;
1596
1597 if (!is_multiview) {
1598 continue;
1599 }
1600
1601 v3d = area->spacedata.first;
1602 if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
1603 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1604 if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
1605 RegionView3D *rv3d = region->regiondata;
1606 if (rv3d->persp == RV3D_CAMOB) {
1607 return true;
1608 }
1609 }
1610 }
1611 }
1612 break;
1613 }
1614 case SPACE_IMAGE: {
1615 SpaceImage *sima;
1616
1617 /* images should always show in stereo, even if
1618 * the file doesn't have views enabled */
1619 sima = area->spacedata.first;
1620 if (sima->image && BKE_image_is_stereo(sima->image) &&
1621 (sima->iuser.flag & IMA_SHOW_STEREO)) {
1622 return true;
1623 }
1624 break;
1625 }
1626 case SPACE_NODE: {
1627 SpaceNode *snode;
1628
1629 if (!is_multiview) {
1630 continue;
1631 }
1632
1633 snode = area->spacedata.first;
1634 if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
1635 return true;
1636 }
1637 break;
1638 }
1639 case SPACE_SEQ: {
1640 SpaceSeq *sseq;
1641
1642 if (!is_multiview) {
1643 continue;
1644 }
1645
1646 sseq = area->spacedata.first;
1647 if (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW)) {
1648 return true;
1649 }
1650
1651 if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
1652 return true;
1653 }
1654
1655 break;
1656 }
1657 }
1658 }
1659
1660 return false;
1661 }
1662
1663 /**
1664 * Find the scene displayed in \a screen.
1665 * \note Assumes \a screen to be visible/active!
1666 */
1667
ED_screen_scene_find_with_window(const bScreen * screen,const wmWindowManager * wm,struct wmWindow ** r_window)1668 Scene *ED_screen_scene_find_with_window(const bScreen *screen,
1669 const wmWindowManager *wm,
1670 struct wmWindow **r_window)
1671 {
1672 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1673 if (WM_window_get_active_screen(win) == screen) {
1674 if (r_window) {
1675 *r_window = win;
1676 }
1677 return WM_window_get_active_scene(win);
1678 }
1679 }
1680
1681 /* Can by NULL when accessing a screen that isn't active. */
1682 return NULL;
1683 }
1684
ED_screen_area_find_with_spacedata(const bScreen * screen,const SpaceLink * sl,const bool only_visible)1685 ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen,
1686 const SpaceLink *sl,
1687 const bool only_visible)
1688 {
1689 if (only_visible) {
1690 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1691 if (area->spacedata.first == sl) {
1692 return area;
1693 }
1694 }
1695 }
1696 else {
1697 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1698 if (BLI_findindex(&area->spacedata, sl) != -1) {
1699 return area;
1700 }
1701 }
1702 }
1703 return NULL;
1704 }
1705
ED_screen_scene_find(const bScreen * screen,const wmWindowManager * wm)1706 Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
1707 {
1708 return ED_screen_scene_find_with_window(screen, wm, NULL);
1709 }
1710
ED_screen_window_find(const bScreen * screen,const wmWindowManager * wm)1711 wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm)
1712 {
1713 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1714 if (WM_window_get_active_screen(win) == screen) {
1715 return win;
1716 }
1717 }
1718 return NULL;
1719 }
1720