Blender V4.3
screen_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cmath>
10#include <cstring>
11
12#include "MEM_guardedalloc.h"
13
14#include "DNA_object_types.h"
15#include "DNA_scene_types.h"
16#include "DNA_userdef_types.h"
17
18#include "BLI_blenlib.h"
19#include "BLI_utildefines.h"
20
21#include "BKE_context.hh"
22#include "BKE_global.hh"
23#include "BKE_icons.h"
24#include "BKE_image.hh"
25#include "BKE_layer.hh"
26#include "BKE_lib_id.hh"
27#include "BKE_main.hh"
28#include "BKE_scene.hh"
29#include "BKE_screen.hh"
30#include "BKE_sound.h"
31#include "BKE_workspace.hh"
32
33#include "WM_api.hh"
34#include "WM_types.hh"
35
36#include "ED_clip.hh"
37#include "ED_node.hh"
38#include "ED_screen.hh"
39#include "ED_screen_types.hh"
40
41#include "RNA_access.hh"
42#include "RNA_enum_types.hh"
43
44#include "UI_interface.hh"
45
46#include "WM_message.hh"
47#include "WM_toolsystem.hh"
48
50
51#include "screen_intern.hh" /* own module include */
52
53/* adds no space data */
55 ScrVert *bottom_left,
56 ScrVert *top_left,
57 ScrVert *top_right,
58 ScrVert *bottom_right,
59 const eSpace_Type space_type)
60{
61 ScrArea *area = static_cast<ScrArea *>(MEM_callocN(sizeof(ScrArea), "addscrarea"));
62
63 area->v1 = bottom_left;
64 area->v2 = top_left;
65 area->v3 = top_right;
66 area->v4 = bottom_right;
67 area->spacetype = space_type;
68
69 BLI_addtail(&area_map->areabase, area);
70
71 return area;
72}
74 ScrVert *left_bottom,
75 ScrVert *left_top,
76 ScrVert *right_top,
77 ScrVert *right_bottom,
78 const eSpace_Type space_type)
79{
80 return screen_addarea_ex(
81 AREAMAP_FROM_SCREEN(screen), left_bottom, left_top, right_top, right_bottom, space_type);
82}
83
84static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
85{
86
87 ED_area_exit(C, area);
88
90
91 BLI_remlink(&screen->areabase, area);
92 MEM_freeN(area);
93}
94
96 bScreen *screen,
97 ScrArea *area,
98 const eScreenAxis dir_axis,
99 const float fac,
100 const bool merge)
101{
102 ScrArea *newa = nullptr;
103
104 if (area == nullptr) {
105 return nullptr;
106 }
107
108 rcti window_rect;
109 WM_window_rect_calc(win, &window_rect);
110
111 short split = screen_geom_find_area_split_point(area, &window_rect, dir_axis, fac);
112 if (split == 0) {
113 return nullptr;
114 }
115
116 /* NOTE(@ideasman42): regarding (fac > 0.5f) checks below.
117 * normally it shouldn't matter which is used since the copy should match the original
118 * however with viewport rendering and python console this isn't the case. */
119
120 if (dir_axis == SCREEN_AXIS_H) {
121 /* new vertices */
122 ScrVert *sv1 = screen_geom_vertex_add(screen, area->v1->vec.x, split);
123 ScrVert *sv2 = screen_geom_vertex_add(screen, area->v4->vec.x, split);
124
125 /* new edges */
126 screen_geom_edge_add(screen, area->v1, sv1);
127 screen_geom_edge_add(screen, sv1, area->v2);
128 screen_geom_edge_add(screen, area->v3, sv2);
129 screen_geom_edge_add(screen, sv2, area->v4);
130 screen_geom_edge_add(screen, sv1, sv2);
131
132 if (fac > 0.5f) {
133 /* new areas: top */
134 newa = screen_addarea(screen, sv1, area->v2, area->v3, sv2, eSpace_Type(area->spacetype));
135
136 /* area below */
137 area->v2 = sv1;
138 area->v3 = sv2;
139 }
140 else {
141 /* new areas: bottom */
142 newa = screen_addarea(screen, area->v1, sv1, sv2, area->v4, eSpace_Type(area->spacetype));
143
144 /* area above */
145 area->v1 = sv1;
146 area->v4 = sv2;
147 }
148
149 ED_area_data_copy(newa, area, true);
150 }
151 else {
152 /* new vertices */
153 ScrVert *sv1 = screen_geom_vertex_add(screen, split, area->v1->vec.y);
154 ScrVert *sv2 = screen_geom_vertex_add(screen, split, area->v2->vec.y);
155
156 /* new edges */
157 screen_geom_edge_add(screen, area->v1, sv1);
158 screen_geom_edge_add(screen, sv1, area->v4);
159 screen_geom_edge_add(screen, area->v2, sv2);
160 screen_geom_edge_add(screen, sv2, area->v3);
161 screen_geom_edge_add(screen, sv1, sv2);
162
163 if (fac > 0.5f) {
164 /* new areas: right */
165 newa = screen_addarea(screen, sv1, sv2, area->v3, area->v4, eSpace_Type(area->spacetype));
166
167 /* area left */
168 area->v3 = sv2;
169 area->v4 = sv1;
170 }
171 else {
172 /* new areas: left */
173 newa = screen_addarea(screen, area->v1, area->v2, sv2, sv1, eSpace_Type(area->spacetype));
174
175 /* area right */
176 area->v1 = sv1;
177 area->v2 = sv2;
178 }
179
180 ED_area_data_copy(newa, area, true);
181 }
182
183 /* remove double vertices en edges */
184 if (merge) {
186 }
189
190 return newa;
191}
192
193bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
194{
195 bScreen *screen = static_cast<bScreen *>(BKE_libblock_alloc(bmain, ID_SCR, name, 0));
196 screen->do_refresh = true;
197 screen->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
198
199 ScrVert *sv1 = screen_geom_vertex_add(screen, rect->xmin, rect->ymin);
200 ScrVert *sv2 = screen_geom_vertex_add(screen, rect->xmin, rect->ymax - 1);
201 ScrVert *sv3 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymax - 1);
202 ScrVert *sv4 = screen_geom_vertex_add(screen, rect->xmax - 1, rect->ymin);
203
204 screen_geom_edge_add(screen, sv1, sv2);
205 screen_geom_edge_add(screen, sv2, sv3);
206 screen_geom_edge_add(screen, sv3, sv4);
207 screen_geom_edge_add(screen, sv4, sv1);
208
209 /* dummy type, no spacedata */
210 screen_addarea(screen, sv1, sv2, sv3, sv4, SPACE_EMPTY);
211
212 return screen;
213}
214
216{
217 /* Free contents of 'to', is from blenkernel `screen.cc`. */
219
220 to->flag = from->flag;
221
222 BLI_duplicatelist(&to->vertbase, &from->vertbase);
223 BLI_duplicatelist(&to->edgebase, &from->edgebase);
224 BLI_duplicatelist(&to->areabase, &from->areabase);
225 BLI_listbase_clear(&to->regionbase);
226
227 ScrVert *s2 = static_cast<ScrVert *>(to->vertbase.first);
228 for (ScrVert *s1 = static_cast<ScrVert *>(from->vertbase.first); s1;
229 s1 = s1->next, s2 = s2->next)
230 {
231 s1->newv = s2;
232 }
233
234 LISTBASE_FOREACH (ScrEdge *, se, &to->edgebase) {
235 se->v1 = se->v1->newv;
236 se->v2 = se->v2->newv;
237 BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
238 }
239
240 ScrArea *from_area = static_cast<ScrArea *>(from->areabase.first);
241 LISTBASE_FOREACH (ScrArea *, area, &to->areabase) {
242 area->v1 = area->v1->newv;
243 area->v2 = area->v2->newv;
244 area->v3 = area->v3->newv;
245 area->v4 = area->v4->newv;
246
247 BLI_listbase_clear(&area->spacedata);
248 BLI_listbase_clear(&area->regionbase);
249 BLI_listbase_clear(&area->actionzones);
250 BLI_listbase_clear(&area->handlers);
251
252 ED_area_data_copy(area, from_area, true);
253
254 from_area = from_area->next;
255 }
256
257 /* put at zero (needed?) */
258 LISTBASE_FOREACH (ScrVert *, s1, &from->vertbase) {
259 s1->newv = nullptr;
260 }
261}
262
263void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
264{
265 screen_new->winid = win->winid;
266 screen_new->do_refresh = true;
267 screen_new->do_draw = true;
268}
269
271{
272 if (sa_a == nullptr || sa_b == nullptr || sa_a == sa_b) {
273 return SCREEN_DIR_NONE;
274 }
275
276 short left_a = sa_a->v1->vec.x;
277 short right_a = sa_a->v3->vec.x;
278 short top_a = sa_a->v3->vec.y;
279 short bottom_a = sa_a->v1->vec.y;
280
281 short left_b = sa_b->v1->vec.x;
282 short right_b = sa_b->v3->vec.x;
283 short top_b = sa_b->v3->vec.y;
284 short bottom_b = sa_b->v1->vec.y;
285
286 /* How much these areas share a common edge. */
287 short overlapx = std::min(right_a, right_b) - std::max(left_a, left_b);
288 short overlapy = std::min(top_a, top_b) - std::max(bottom_a, bottom_b);
289
290 /* Minimum overlap required. */
291 const short minx = std::min({int(AREAJOINTOLERANCEX), right_a - left_a, right_b - left_b});
292 const short miny = std::min({int(AREAJOINTOLERANCEY), top_a - bottom_a, top_b - bottom_b});
293
294 if (top_a == bottom_b && overlapx >= minx) {
295 return eScreenDir(1); /* sa_a to bottom of sa_b = N */
296 }
297 if (bottom_a == top_b && overlapx >= minx) {
298 return eScreenDir(3); /* sa_a on top of sa_b = S */
299 }
300 if (left_a == right_b && overlapy >= miny) {
301 return eScreenDir(0); /* sa_a to right of sa_b = W */
302 }
303 if (right_a == left_b && overlapy >= miny) {
304 return eScreenDir(2); /* sa_a to left of sa_b = E */
305 }
306
307 return eScreenDir(-1);
308}
309
311 ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
312{
313 if (sa_a == nullptr || sa_b == nullptr) {
314 *r_offset1 = INT_MAX;
315 *r_offset2 = INT_MAX;
316 }
317 else if (dir == SCREEN_DIR_W) { /* West: sa on right and sa_b to the left. */
318 *r_offset1 = sa_b->v3->vec.y - sa_a->v2->vec.y;
319 *r_offset2 = sa_b->v4->vec.y - sa_a->v1->vec.y;
320 }
321 else if (dir == SCREEN_DIR_N) { /* North: sa below and sa_b above. */
322 *r_offset1 = sa_a->v2->vec.x - sa_b->v1->vec.x;
323 *r_offset2 = sa_a->v3->vec.x - sa_b->v4->vec.x;
324 }
325 else if (dir == SCREEN_DIR_E) { /* East: sa on left and sa_b to the right. */
326 *r_offset1 = sa_b->v2->vec.y - sa_a->v3->vec.y;
327 *r_offset2 = sa_b->v1->vec.y - sa_a->v4->vec.y;
328 }
329 else if (dir == SCREEN_DIR_S) { /* South: sa above and sa_b below. */
330 *r_offset1 = sa_a->v1->vec.x - sa_b->v2->vec.x;
331 *r_offset2 = sa_a->v4->vec.x - sa_b->v3->vec.x;
332 }
333 else {
335 *r_offset1 = INT_MAX;
336 *r_offset2 = INT_MAX;
337 }
338}
339
340/* Screen verts with horizontal position equal to from_x are moved to to_x. */
341static void screen_verts_halign(const wmWindow *win,
342 const bScreen *screen,
343 const short from_x,
344 const short to_x)
345{
346 ED_screen_verts_iter(win, screen, v1)
347 {
348 if (v1->vec.x == from_x) {
349 v1->vec.x = to_x;
350 }
351 }
352}
353
354/* Screen verts with vertical position equal to from_y are moved to to_y. */
355static void screen_verts_valign(const wmWindow *win,
356 const bScreen *screen,
357 const short from_y,
358 const short to_y)
359{
360 ED_screen_verts_iter(win, screen, v1)
361 {
362 if (v1->vec.y == from_y) {
363 v1->vec.y = to_y;
364 }
365 }
366}
367
368/* Test if two adjoining areas can be aligned by having their screen edges adjusted. */
369static bool screen_areas_can_align(bScreen *screen, ScrArea *sa1, ScrArea *sa2, eScreenDir dir)
370{
371 if (dir == SCREEN_DIR_NONE) {
372 return false;
373 }
374
375 int offset1;
376 int offset2;
377 area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
378
380 if ((abs(offset1) >= tolerance) || (abs(offset2) >= tolerance)) {
381 /* Misalignment is too great. */
382 return false;
383 }
384
385 /* Areas that are _smaller_ than minimum sizes, sharing an edge to be moved. See #100772. */
386 if (SCREEN_DIR_IS_VERTICAL(dir)) {
387 const short xmin = std::min(sa1->v1->vec.x, sa2->v1->vec.x);
388 const short xmax = std::max(sa1->v3->vec.x, sa2->v3->vec.x);
389 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
390 if (ELEM(area, sa1, sa2)) {
391 continue;
392 }
393 if (area->v3->vec.x - area->v1->vec.x < tolerance &&
394 (area->v1->vec.x == xmin || area->v3->vec.x == xmax))
395 {
396 WM_report(RPT_ERROR, "A narrow vertical area interferes with this operation");
397 return false;
398 }
399 }
400 }
401 else {
402 const short ymin = std::min(sa1->v1->vec.y, sa2->v1->vec.y);
403 const short ymax = std::max(sa1->v3->vec.y, sa2->v3->vec.y);
404 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
405 if (ELEM(area, sa1, sa2)) {
406 continue;
407 }
408 if (area->v3->vec.y - area->v1->vec.y < tolerance &&
409 (area->v1->vec.y == ymin || area->v3->vec.y == ymax))
410 {
411 WM_report(RPT_ERROR, "A narrow horizontal area interferes with this operation");
412 return false;
413 }
414 }
415 }
416
417 return true;
418}
419
420/* Adjust all screen edges to allow joining two areas. 'dir' value is like area_getorientation().
421 */
423 bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const eScreenDir dir)
424{
425 if (!screen_areas_can_align(screen, sa1, sa2, dir)) {
426 return false;
427 }
428
429 wmWindow *win = CTX_wm_window(C);
430
431 if (SCREEN_DIR_IS_HORIZONTAL(dir)) {
432 /* horizontal join, use average for new top and bottom. */
433 int top = (sa1->v2->vec.y + sa2->v2->vec.y) / 2;
434 int bottom = (sa1->v4->vec.y + sa2->v4->vec.y) / 2;
435
436 /* Move edges exactly matching source top and bottom. */
437 screen_verts_valign(win, screen, sa1->v2->vec.y, top);
438 screen_verts_valign(win, screen, sa1->v4->vec.y, bottom);
439
440 /* Move edges exactly matching target top and bottom. */
441 screen_verts_valign(win, screen, sa2->v2->vec.y, top);
442 screen_verts_valign(win, screen, sa2->v4->vec.y, bottom);
443 }
444 else {
445 /* Vertical join, use averages for new left and right. */
446 int left = (sa1->v1->vec.x + sa2->v1->vec.x) / 2;
447 int right = (sa1->v3->vec.x + sa2->v3->vec.x) / 2;
448
449 /* Move edges exactly matching source left and right. */
450 screen_verts_halign(win, screen, sa1->v1->vec.x, left);
451 screen_verts_halign(win, screen, sa1->v3->vec.x, right);
452
453 /* Move edges exactly matching target left and right */
454 screen_verts_halign(win, screen, sa2->v1->vec.x, left);
455 screen_verts_halign(win, screen, sa2->v3->vec.x, right);
456 }
457
458 return true;
459}
460
461/* Simple join of two areas without any splitting. Will return false if not possible. */
462static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
463{
464 const eScreenDir dir = area_getorientation(sa1, sa2);
465
466 /* Ensure that the area edges are exactly aligned. */
467 if (!screen_areas_align(C, screen, sa1, sa2, dir)) {
468 return false;
469 }
470
471 if (dir == SCREEN_DIR_W) { /* sa1 to right of sa2 = West. */
472 sa1->v1 = sa2->v1; /* BL */
473 sa1->v2 = sa2->v2; /* TL */
474 screen_geom_edge_add(screen, sa1->v2, sa1->v3);
475 screen_geom_edge_add(screen, sa1->v1, sa1->v4);
476 }
477 else if (dir == SCREEN_DIR_N) { /* sa1 to bottom of sa2 = North. */
478 sa1->v2 = sa2->v2; /* TL */
479 sa1->v3 = sa2->v3; /* TR */
480 screen_geom_edge_add(screen, sa1->v1, sa1->v2);
481 screen_geom_edge_add(screen, sa1->v3, sa1->v4);
482 }
483 else if (dir == SCREEN_DIR_E) { /* sa1 to left of sa2 = East. */
484 sa1->v3 = sa2->v3; /* TR */
485 sa1->v4 = sa2->v4; /* BR */
486 screen_geom_edge_add(screen, sa1->v2, sa1->v3);
487 screen_geom_edge_add(screen, sa1->v1, sa1->v4);
488 }
489 else if (dir == SCREEN_DIR_S) { /* sa1 on top of sa2 = South. */
490 sa1->v1 = sa2->v1; /* BL */
491 sa1->v4 = sa2->v4; /* BR */
492 screen_geom_edge_add(screen, sa1->v1, sa1->v2);
493 screen_geom_edge_add(screen, sa1->v3, sa1->v4);
494 }
495
496 screen_delarea(C, screen, sa2);
498 /* Update preview thumbnail */
499 BKE_icon_changed(screen->id.icon_id);
500
501 return true;
502}
503
504/* Slice off and return new area. "Reverse" gives right/bottom, rather than left/top. */
506 bContext *C, bScreen *screen, ScrArea **area, int size, eScreenDir dir, bool reverse)
507{
508 const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
509 if (abs(size) < (vertical ? AREAJOINTOLERANCEX : AREAJOINTOLERANCEY)) {
510 return nullptr;
511 }
512
513 /* Measurement with ScrVerts because winx and winy might not be correct at this time. */
514 float fac = abs(size) / float(vertical ? ((*area)->v3->vec.x - (*area)->v1->vec.x) :
515 ((*area)->v3->vec.y - (*area)->v1->vec.y));
516 fac = (reverse == vertical) ? 1.0f - fac : fac;
517 ScrArea *newsa = area_split(
518 CTX_wm_window(C), screen, *area, vertical ? SCREEN_AXIS_V : SCREEN_AXIS_H, fac, true);
519
520 /* area_split always returns smallest of the two areas, so might have to swap. */
521 if (((fac > 0.5f) == vertical) != reverse) {
522 ScrArea *temp = *area;
523 *area = newsa;
524 newsa = temp;
525 }
526
527 return newsa;
528}
529
530/* Join any two neighboring areas. Might create new areas, kept if over min_remainder. */
532 bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, bool close_all_remainders)
533{
534 const eScreenDir dir = area_getorientation(sa1, sa2);
535 if (dir == SCREEN_DIR_NONE) {
536 return false;
537 }
538
539 int offset1;
540 int offset2;
541 area_getoffsets(sa1, sa2, dir, &offset1, &offset2);
542
543 /* Split Left/Top into new area if overhanging. */
544 ScrArea *side1 = screen_area_trim(C, screen, (offset1 > 0) ? &sa2 : &sa1, offset1, dir, false);
545
546 /* Split Right/Bottom into new area if overhanging. */
547 ScrArea *side2 = screen_area_trim(C, screen, (offset2 > 0) ? &sa1 : &sa2, offset2, dir, true);
548
549 /* The two areas now line up, so join them. */
550 screen_area_join_aligned(C, screen, sa1, sa2);
551
552 if (close_all_remainders || offset1 < 0 || offset2 > 0) {
553 /* Close both if trimming `sa1`. */
554 screen_area_close(C, screen, side1);
555 screen_area_close(C, screen, side2);
556 }
557
558 BKE_icon_changed(screen->id.icon_id);
559 return true;
560}
561
562int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
563{
564 return screen_area_join_ex(C, screen, sa1, sa2, false);
565}
566
568{
569 if (area == nullptr) {
570 return false;
571 }
572
573 ScrArea *sa2 = nullptr;
574 float best_alignment = 0.0f;
575
576 LISTBASE_FOREACH (ScrArea *, neighbor, &screen->areabase) {
577 const eScreenDir dir = area_getorientation(area, neighbor);
578 /* Must at least partially share an edge and not be a global area. */
579 if ((dir != SCREEN_DIR_NONE) && (neighbor->global == nullptr)) {
580 /* Winx/Winy might not be updated yet, so get lengths from verts. */
581 const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
582 const int area_length = vertical ? (area->v3->vec.x - area->v1->vec.x) :
583 (area->v3->vec.y - area->v1->vec.y);
584 const int ar_length = vertical ? (neighbor->v3->vec.x - neighbor->v1->vec.x) :
585 (neighbor->v3->vec.y - neighbor->v1->vec.y);
586 /* Calculate the ratio of the lengths of the shared edges. */
587 float alignment = std::min(area_length, ar_length) / float(std::max(area_length, ar_length));
588 if (alignment > best_alignment) {
589 best_alignment = alignment;
590 sa2 = neighbor;
591 }
592 }
593 }
594
595 /* Join from neighbor into this area to close it. */
596 return screen_area_join_ex(C, screen, sa2, area, true);
597}
598
599void screen_area_spacelink_add(const Scene *scene, ScrArea *area, eSpace_Type space_type)
600{
601 SpaceType *stype = BKE_spacetype_from_id(space_type);
602 SpaceLink *slink = stype->create(area, scene);
603
604 area->regionbase = slink->regionbase;
605
606 BLI_addhead(&area->spacedata, slink);
608}
609
610/* ****************** EXPORTED API TO OTHER MODULES *************************** */
611
612/* screen sets cursor based on active region */
613static void region_cursor_set_ex(wmWindow *win, ScrArea *area, ARegion *region, bool swin_changed)
614{
615 BLI_assert(WM_window_get_active_screen(win)->active_region == region);
616 if (win->tag_cursor_refresh || swin_changed || (region->type && region->type->event_cursor)) {
617 win->tag_cursor_refresh = false;
618 ED_region_cursor_set(win, area, region);
619 }
620}
621
622static void region_cursor_set(wmWindow *win, bool swin_changed)
623{
625
626 ED_screen_areas_iter (win, screen, area) {
627 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
628 if (region == screen->active_region) {
629 region_cursor_set_ex(win, area, region, swin_changed);
630 return;
631 }
632 }
633 }
634}
635
637{
638 wmWindow *win = CTX_wm_window(C);
639 bScreen *screen = CTX_wm_screen(C);
640
641 /* generic notes */
642 switch (note->category) {
643 case NC_WM:
644 if (note->data == ND_FILEREAD) {
645 screen->do_draw = true;
646 }
647 break;
648 case NC_WINDOW:
649 screen->do_draw = true;
650 break;
651 case NC_SCREEN:
652 if (note->action == NA_EDITED) {
653 screen->do_draw = screen->do_refresh = true;
654 }
655 break;
656 case NC_SCENE:
657 if (note->data == ND_MODE) {
658 region_cursor_set(win, true);
659 }
660 break;
661 }
662}
663
664static bool region_poll(const bContext *C,
665 const bScreen *screen,
666 const ScrArea *area,
667 const ARegion *region)
668{
669 if (!region->type || !region->type->poll) {
670 /* Show region by default. */
671 return true;
672 }
673
674 RegionPollParams params = {nullptr};
675 params.screen = screen;
676 params.area = area;
677 params.region = region;
678 params.context = C;
679
680 return region->type->poll(&params);
681}
682
686static bool screen_regions_poll(bContext *C, wmWindow *win, const bScreen *screen)
687{
688 wmWindow *prev_win = CTX_wm_window(C);
689 ScrArea *prev_area = CTX_wm_area(C);
690 ARegion *prev_region = CTX_wm_region(C);
691
692 CTX_wm_window_set(C, win);
693
694 bool any_changed = false;
695 ED_screen_areas_iter (win, screen, area) {
696 CTX_wm_area_set(C, area);
697
698 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
699 const int old_region_flag = region->flag;
700
701 region->flag &= ~RGN_FLAG_POLL_FAILED;
702
703 CTX_wm_region_set(C, region);
704 if (region_poll(C, screen, area, region) == false) {
705 region->flag |= RGN_FLAG_POLL_FAILED;
706 }
707 else if (region->type && region->type->on_poll_success) {
708 region->type->on_poll_success(C, region);
709 }
710
711 if (old_region_flag != region->flag) {
712 any_changed = true;
713
714 /* Enforce complete re-init. */
715 region->v2d.flag &= ~V2D_IS_INIT;
716 ED_region_visibility_change_update(C, area, region);
717 }
718 }
719 }
720
721 CTX_wm_window_set(C, prev_win);
722 CTX_wm_area_set(C, prev_area);
723 CTX_wm_region_set(C, prev_region);
724
725 return any_changed;
726}
727
733 wmWindowManager *wm,
734 wmWindow *win,
735 const bool force_full_refresh)
736{
738 bool do_refresh = screen->do_refresh;
739
740 /* Returns true if a change was done that requires refreshing. */
741 if (screen_regions_poll(C, win, screen)) {
742 do_refresh = true;
743 }
744
745 if (!force_full_refresh && !do_refresh) {
746 return;
747 }
748
749 /* Exception for background mode, we only need the screen context. */
750 if (!G.background) {
751
752 /* Called even when creating the ghost window fails in #WM_window_open. */
753 if (win->ghostwin) {
754 /* Header size depends on DPI, let's verify. */
756 }
757
759
760 screen_geom_vertices_scale(win, screen);
761
762 ED_screen_areas_iter (win, screen, area) {
763 /* Set space-type and region callbacks, calls init() */
764 /* Sets sub-windows for regions, adds handlers. */
765 ED_area_init(wm, win, area);
766 }
767
768 /* wake up animtimer */
769 if (screen->animtimer) {
770 WM_event_timer_sleep(wm, win, screen->animtimer, false);
771 }
772 }
773
774 if (G.debug & G_DEBUG_EVENTS) {
775 printf("%s: set screen\n", __func__);
776 }
777 screen->do_refresh = false;
778 /* Prevent multi-window errors. */
779 screen->winid = win->winid;
780
781 screen->context = reinterpret_cast<void *>(ed_screen_context);
782}
783
785{
786 screen_refresh(C, wm, win, /*force_full_refresh=*/true);
787}
788
790{
791 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
792 if (BKE_workspace_active_get(win->workspace_hook) == nullptr) {
793 BKE_workspace_active_set(win->workspace_hook,
794 static_cast<WorkSpace *>(bmain->workspaces.first));
795 }
796
797 ED_screen_refresh(C, wm, win);
798 if (win->eventstate) {
799 ED_screen_set_active_region(nullptr, win, win->eventstate->xy);
800 }
801 }
802
803 if (U.uiflag & USER_HEADER_FROM_PREF) {
804 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
806 }
807 }
808}
809
811{
812 /* Only do a full refresh if required (checks #bScreen.do_refresh tag). */
813 const bool force_full_refresh = false;
814 screen_refresh(C, wm, win, force_full_refresh);
815}
816
817void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
818{
819 ED_region_exit(C, region);
820 BKE_area_region_free(area->type, region);
821 BLI_freelinkN(&area->regionbase, region);
822}
823
824/* *********** exit calls are for closing running stuff ******** */
825
827{
829 wmWindow *win = CTX_wm_window(C);
830 ARegion *prevar = CTX_wm_region(C);
831
832 if (region->type && region->type->exit) {
833 region->type->exit(wm, region);
834 }
835
836 CTX_wm_region_set(C, region);
837
838 WM_event_remove_handlers(C, &region->handlers);
839 WM_event_modal_handler_region_replace(win, region, nullptr);
840
841 if (region->regiontype == RGN_TYPE_TEMPORARY) {
842 /* This may be a popup region such as a popover or splash screen.
843 * In the case of popups which spawn popups it's possible for
844 * the parent popup to be freed *before* a popup which created it.
845 * The child may have a reference to the freed parent unless cleared here, see: #122132.
846 *
847 * Having parent popups freed before the popups they spawn could be investigated although
848 * they're not technically nested as they're both stored in #Screen::regionbase. */
849 WM_event_ui_handler_region_popup_replace(win, region, nullptr);
850 }
851
852 WM_draw_region_free(region);
853 /* The region is not in a state that it can be visible in anymore. Reinitializing is needed. */
854 region->visible = false;
855
856 MEM_SAFE_FREE(region->headerstr);
857
858 if (region->regiontimer) {
859 WM_event_timer_remove(wm, win, region->regiontimer);
860 region->regiontimer = nullptr;
861 }
862
864
865 CTX_wm_region_set(C, prevar);
866}
867
869{
871 wmWindow *win = CTX_wm_window(C);
872 ScrArea *prevsa = CTX_wm_area(C);
873
874 if (area->type && area->type->exit) {
875 area->type->exit(wm, area);
876 }
877
878 CTX_wm_area_set(C, area);
879
880 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
881 ED_region_exit(C, region);
882 }
883
884 WM_event_remove_handlers(C, &area->handlers);
885 WM_event_modal_handler_area_replace(win, area, nullptr);
886
887 CTX_wm_area_set(C, prevsa);
888}
889
890void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
891{
893 wmWindow *prevwin = CTX_wm_window(C);
894
895 CTX_wm_window_set(C, window);
896
897 if (screen->animtimer) {
898 WM_event_timer_remove(wm, window, screen->animtimer);
899
901 Scene *scene = WM_window_get_active_scene(prevwin);
902 Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
903 BKE_sound_stop_scene(scene_eval);
904 }
905 screen->animtimer = nullptr;
906 screen->scrubbing = false;
907
908 screen->active_region = nullptr;
909
910 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
911 ED_region_exit(C, region);
912 }
913 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
914 ED_area_exit(C, area);
915 }
916 /* Don't use ED_screen_areas_iter here, it skips hidden areas. */
917 LISTBASE_FOREACH (ScrArea *, area, &window->global_areas.areabase) {
918 ED_area_exit(C, area);
919 }
920
921 /* mark it available for use for other windows */
922 screen->winid = 0;
923
924 if (!WM_window_is_temp_screen(prevwin)) {
925 /* use previous window if possible */
926 CTX_wm_window_set(C, prevwin);
927 }
928 else {
929 /* none otherwise */
930 CTX_wm_window_set(C, nullptr);
931 }
932}
933
935{
936 if (area->type && area->type->space_name_get) {
937 return area->type->space_name_get(area);
938 }
939
940 const int index = RNA_enum_from_value(rna_enum_space_type_items, area->spacetype);
942 return item.name;
943}
944
945int ED_area_icon(const ScrArea *area)
946{
947 if (area->type && area->type->space_icon_get) {
948 return area->type->space_icon_get(area);
949 }
950
951 const int index = RNA_enum_from_value(rna_enum_space_type_items, area->spacetype);
953 return item.icon;
954}
955
956/* *********************************** */
957
958/* case when on area-edge or in azones, or outside window */
959static void screen_cursor_set(wmWindow *win, const int xy[2])
960{
961 const bScreen *screen = WM_window_get_active_screen(win);
962 AZone *az = nullptr;
963 ScrArea *area = nullptr;
964
965 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
966 az = ED_area_actionzone_find_xy(area_iter, xy);
967 /* Scrollers use default cursor and their zones extend outside of their
968 * areas. Ignore here so we can always detect screen edges - #110085. */
969 if (az && az->type != AZONE_REGION_SCROLL) {
970 area = area_iter;
971 break;
972 }
973 }
974
975 if (area) {
976 if (az->type == AZONE_AREA) {
978 }
979 else if (az->type == AZONE_REGION) {
982 }
983 else {
985 }
986 }
987 }
988 else {
989 ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, xy[0], xy[1]);
990
991 if (actedge) {
992 if (screen_geom_edge_is_horizontal(actedge)) {
994 }
995 else {
997 }
998 }
999 else {
1001 }
1002 }
1003}
1004
1006{
1007 bScreen *screen = WM_window_get_active_screen(win);
1008 if (screen == nullptr) {
1009 return;
1010 }
1011
1012 ScrArea *area = nullptr;
1013 ARegion *region_prev = screen->active_region;
1014
1015 ED_screen_areas_iter (win, screen, area_iter) {
1016 if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) &&
1017 xy[0] < (area_iter->totrct.xmax - BORDERPADDING))
1018 {
1019 if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) &&
1020 xy[1] < (area_iter->totrct.ymax - BORDERPADDING))
1021 {
1022 if (ED_area_azones_update(area_iter, xy) == nullptr) {
1023 area = area_iter;
1024 break;
1025 }
1026 }
1027 }
1028 }
1029 if (area) {
1030 /* Make overlap active when mouse over. */
1031 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1032 if (ED_region_contains_xy(region, xy)) {
1033 screen->active_region = region;
1034 break;
1035 }
1036 }
1037 }
1038 else {
1039 screen->active_region = nullptr;
1040 }
1041
1042 if (region_prev != screen->active_region || !screen->active_region) {
1044 }
1045
1046 /* Check for redraw headers. */
1047 if (region_prev != screen->active_region) {
1048
1049 ED_screen_areas_iter (win, screen, area_iter) {
1050 bool do_draw = false;
1051
1052 LISTBASE_FOREACH (ARegion *, region, &area_iter->regionbase) {
1053 /* Call old area's deactivate if assigned. */
1054 if (region == region_prev && area_iter->type && area_iter->type->deactivate) {
1055 area_iter->type->deactivate(area_iter);
1056 }
1057
1058 if (region == region_prev && region != screen->active_region) {
1059 wmGizmoMap *gzmap = region_prev->gizmo_map;
1060 if (gzmap) {
1061 if (WM_gizmo_highlight_set(gzmap, nullptr)) {
1063 }
1064 }
1065 }
1066
1067 if (ELEM(region, region_prev, screen->active_region)) {
1068 do_draw = true;
1069 }
1070 }
1071
1072 if (do_draw) {
1073 LISTBASE_FOREACH (ARegion *, region, &area_iter->regionbase) {
1074 if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
1076 }
1077 }
1078 }
1079 }
1080
1081 /* Ensure test-motion values are never shared between regions. */
1082 const int mval[2] = {-1, -1};
1083 const bool use_cycle = !WM_cursor_test_motion_and_update(mval);
1084 UNUSED_VARS(use_cycle);
1085 }
1086
1087 /* Cursors, for time being set always on edges,
1088 * otherwise the active region doesn't switch. */
1089 if (screen->active_region == nullptr) {
1090 screen_cursor_set(win, xy);
1091 }
1092 else {
1093 /* Notifier invokes freeing the buttons... causing a bit too much redraws. */
1094 region_cursor_set_ex(win, area, screen->active_region, region_prev != screen->active_region);
1095
1096 if (region_prev != screen->active_region) {
1097 /* This used to be a notifier, but needs to be done immediate
1098 * because it can undo setting the right button as active due
1099 * to delayed notifier handling. */
1100 if (C) {
1102 }
1103 }
1104 }
1105}
1106
1108{
1109 wmWindow *win = CTX_wm_window(C);
1110 bScreen *screen = CTX_wm_screen(C);
1111 ScrArea *area = CTX_wm_area(C);
1112
1113 if (win && screen && area) {
1114 AZone *az = ED_area_actionzone_find_xy(area, win->eventstate->xy);
1115
1116 if (az && az->type == AZONE_REGION) {
1117 return 1;
1118 }
1119
1120 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1121 if (region == screen->active_region) {
1122 return 1;
1123 }
1124 }
1125 }
1126 return 0;
1127}
1128
1134 const rcti *rect,
1135 eSpace_Type space_type)
1136{
1137 ScrVert *bottom_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin);
1138 ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax);
1139 ScrVert *top_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymax);
1140 ScrVert *bottom_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymin);
1141
1142 screen_geom_edge_add_ex(area_map, bottom_left, top_left);
1143 screen_geom_edge_add_ex(area_map, top_left, top_right);
1144 screen_geom_edge_add_ex(area_map, top_right, bottom_right);
1145 screen_geom_edge_add_ex(area_map, bottom_right, bottom_left);
1146
1147 return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, space_type);
1148}
1149
1150static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
1151{
1152 area->v1->vec.x = rect->xmin;
1153 area->v1->vec.y = rect->ymin;
1154 area->v2->vec.x = rect->xmin;
1155 area->v2->vec.y = rect->ymax;
1156 area->v3->vec.x = rect->xmax;
1157 area->v3->vec.y = rect->ymax;
1158 area->v4->vec.x = rect->xmax;
1159 area->v4->vec.y = rect->ymin;
1160}
1161
1163 bScreen *screen,
1164 const eSpace_Type space_type,
1165 GlobalAreaAlign align,
1166 const rcti *rect,
1167 const short height_cur,
1168 const short height_min,
1169 const short height_max)
1170{
1171 /* Full-screens shouldn't have global areas. Don't touch them. */
1172 if (screen->state == SCREENFULL) {
1173 return;
1174 }
1175
1176 ScrArea *area = nullptr;
1177 LISTBASE_FOREACH (ScrArea *, area_iter, &win->global_areas.areabase) {
1178 if (area_iter->spacetype == space_type) {
1179 area = area_iter;
1180 break;
1181 }
1182 }
1183
1184 if (area) {
1186 }
1187 else {
1188 area = screen_area_create_with_geometry(&win->global_areas, rect, space_type);
1190
1191 /* Data specific to global areas. */
1192 area->global = static_cast<ScrGlobalAreaData *>(MEM_callocN(sizeof(*area->global), __func__));
1193 area->global->size_max = height_max;
1194 area->global->size_min = height_min;
1195 area->global->align = align;
1196 }
1197
1198 if (area->global->cur_fixed_height != height_cur) {
1199 /* Refresh layout if size changes. */
1200 area->global->cur_fixed_height = height_cur;
1201 screen->do_refresh = true;
1202 }
1203}
1204
1206{
1208}
1209
1211{
1212 const blender::int2 win_size = WM_window_native_pixel_size(win);
1213 const short size = screen_global_header_size();
1214 rcti rect;
1215
1216 BLI_rcti_init(&rect, 0, win_size[0] - 1, 0, win_size[1] - 1);
1217 rect.ymin = rect.ymax - size;
1218
1220 win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size, size);
1221}
1222
1224{
1225 const blender::int2 win_size = WM_window_native_pixel_size(win);
1226 const short size_min = 1;
1227 const short size_max = 0.85f * screen_global_header_size();
1228 const short size = (screen->flag & SCREEN_COLLAPSE_STATUSBAR) ? size_min : size_max;
1229 rcti rect;
1230
1231 BLI_rcti_init(&rect, 0, win_size[0] - 1, 0, win_size[1] - 1);
1232 rect.ymax = rect.ymin + size_max;
1233
1235 win, screen, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size, size_min, size_max);
1236}
1237
1239{
1240 /* Update screen flags from height in window, this is weak and perhaps
1241 * global areas should just become part of the screen instead. */
1243
1244 screen->flag &= ~SCREEN_COLLAPSE_STATUSBAR;
1245
1247 if (area->global->cur_fixed_height == area->global->size_min) {
1248 if (area->spacetype == SPACE_STATUSBAR) {
1249 screen->flag |= SCREEN_COLLAPSE_STATUSBAR;
1250 }
1251 }
1252 }
1253}
1254
1256{
1257 /* Don't create global area for child and temporary windows. */
1259 if ((win->parent != nullptr) || screen->temp) {
1260 if (win->global_areas.areabase.first) {
1261 screen->do_refresh = true;
1263 }
1264 return;
1265 }
1266
1269}
1270
1271/* -------------------------------------------------------------------- */
1272/* Screen changing */
1273
1275 bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
1276{
1277 UNUSED_VARS_NDEBUG(bmain);
1278 BLI_assert(BLI_findindex(&bmain->screens, screen_new) != -1);
1279
1280 if (screen_old != screen_new) {
1281 wmTimer *wt = screen_old->animtimer;
1282
1283 /* remove handlers referencing areas in old screen */
1284 LISTBASE_FOREACH (ScrArea *, area, &screen_old->areabase) {
1286 }
1287
1288 /* we put timer to sleep, so screen_exit has to think there's no timer */
1289 screen_old->animtimer = nullptr;
1290 if (wt) {
1291 WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
1292 }
1293 ED_screen_exit(C, win, screen_old);
1294
1295 /* Same scene, "transfer" playback to new screen. */
1296 if (wt) {
1297 screen_new->animtimer = wt;
1298 }
1299 }
1300}
1301
1303{
1304 Scene *scene = WM_window_get_active_scene(win);
1306 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
1307
1308 CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
1309
1311
1312 BKE_screen_view3d_scene_sync(screen, scene); /* sync new screen with scene data */
1313 WM_event_add_notifier(C, NC_WINDOW, nullptr);
1315
1316 /* Makes button highlights work. */
1318}
1319
1321{
1322 Main *bmain = CTX_data_main(C);
1323 wmWindow *win = CTX_wm_window(C);
1325 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
1326 bScreen *screen_old = CTX_wm_screen(C);
1327
1328 /* Get the actual layout/screen to be activated (guaranteed to be unused, even if that means
1329 * having to duplicate an existing one). */
1331 bmain, workspace, layout, layout, win);
1332 bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
1333
1334 screen_change_prepare(screen_old, screen_new, bmain, C, win);
1335
1336 if (screen_old != screen_new) {
1337 WM_window_set_active_screen(win, workspace, screen_new);
1338 screen_change_update(C, win, screen_new);
1339
1340 return true;
1341 }
1342
1343 return false;
1344}
1345
1347 ViewLayer *view_layer,
1348 ScrArea *area,
1349 View3D *v3d)
1350{
1351 /* fix any cameras that are used in the 3d view but not in the scene */
1352 BKE_screen_view3d_sync(v3d, scene);
1353
1354 BKE_view_layer_synced_ensure(scene, view_layer);
1355 if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
1356 v3d->camera = BKE_view_layer_camera_find(scene, view_layer);
1357 // XXX if (screen == curscreen) handle_view3d_lock();
1358 if (!v3d->camera) {
1359 ListBase *regionbase;
1360
1361 /* regionbase is in different place depending if space is active */
1362 if (v3d == area->spacedata.first) {
1363 regionbase = &area->regionbase;
1364 }
1365 else {
1366 regionbase = &v3d->regionbase;
1367 }
1368
1369 LISTBASE_FOREACH (ARegion *, region, regionbase) {
1370 if (region->regiontype == RGN_TYPE_WINDOW) {
1371 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1372 if (rv3d->persp == RV3D_CAMOB) {
1373 rv3d->persp = RV3D_PERSP;
1374 }
1375 }
1376 }
1377 }
1378 }
1379}
1380
1382 wmWindow *win,
1383 Scene *scene,
1384 const bool refresh_toolsystem)
1385{
1386#if 0
1387 ViewLayer *view_layer_old = WM_window_get_active_view_layer(win);
1388#endif
1389
1390 /* Switch scene. */
1391 win->scene = scene;
1392 if (CTX_wm_window(C) == win) {
1393 CTX_data_scene_set(C, scene);
1394 }
1395
1396 /* Ensure the view layer name is updated. */
1398 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
1399
1400#if 0
1401 /* Mode Syncing. */
1402 if (view_layer_old) {
1403 WorkSpace *workspace = CTX_wm_workspace(C);
1404 Object *obact_new = BKE_view_layer_active_object_get(view_layer);
1405 UNUSED_VARS(obact_new);
1406 eObjectMode object_mode_old = workspace->object_mode;
1407 Object *obact_old = BKE_view_layer_active_object_get(view_layer_old);
1408 UNUSED_VARS(obact_old, object_mode_old);
1409 }
1410#endif
1411
1412 /* Update 3D view cameras. */
1413 const bScreen *screen = WM_window_get_active_screen(win);
1414 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1415 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
1416 if (sl->spacetype == SPACE_VIEW3D) {
1417 View3D *v3d = (View3D *)sl;
1418 screen_set_3dview_camera(scene, view_layer, area, v3d);
1419 }
1420 }
1421 }
1422
1423 if (refresh_toolsystem) {
1425 }
1426}
1427
1429{
1430 bScreen *newscreen = nullptr;
1431 ScrArea *newsa = nullptr;
1432 SpaceLink *newsl;
1433
1434 if (!area || area->full == nullptr) {
1435 newscreen = ED_screen_state_maximized_create(C);
1436 newsa = static_cast<ScrArea *>(newscreen->areabase.first);
1437 BLI_assert(newsa->spacetype == SPACE_EMPTY);
1438 }
1439
1440 if (!newsa) {
1441 newsa = area;
1442 }
1443
1444 BLI_assert(newsa);
1445 newsl = static_cast<SpaceLink *>(newsa->spacedata.first);
1446
1447 /* Tag the active space before changing, so we can identify it when user wants to go back. */
1448 if (newsl && (newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) {
1450 }
1451
1452 ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY));
1453
1454 if (newscreen) {
1455 ED_screen_change(C, newscreen);
1456 }
1457
1458 return newsa;
1459}
1460
1462{
1463 BLI_assert(area->full);
1464
1465 if (area->flag & AREA_FLAG_STACKED_FULLSCREEN) {
1466 /* Stacked full-screen -> only go back to previous area and don't toggle out of full-screen. */
1467 ED_area_prevspace(C, area);
1468 }
1469 else {
1471 }
1472}
1473
1475{
1476 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
1477
1478 /* In case nether functions below run. */
1479 ED_area_tag_redraw(area);
1480
1482 ED_area_prevspace(C, area);
1483 }
1484
1485 if (area->full) {
1487 }
1488}
1489
1491{
1492 wmWindow *win = CTX_wm_window(C);
1493 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
1494 bScreen *screen = CTX_wm_screen(C);
1495 short state = (screen ? screen->state : short(SCREENMAXIMIZED));
1496
1497 /* If full-screen area has a temporary space (such as a file browser or full-screen render
1498 * overlaid on top of an existing setup) then return to the previous space. */
1499
1500 if (sl->next) {
1502 ED_screen_full_prevspace(C, area);
1503 }
1504 else {
1505 ED_screen_state_toggle(C, win, area, state);
1506 }
1507 /* WARNING: 'area' may be freed */
1508 }
1509 /* otherwise just tile the area again */
1510 else {
1511 ED_screen_state_toggle(C, win, area, state);
1512 }
1513}
1514
1525 wmWindow *win,
1526 ScrArea *toggle_area,
1527 int state)
1528{
1529 Main *bmain = CTX_data_main(C);
1530 WorkSpace *workspace = WM_window_get_active_workspace(win);
1531
1532 /* change from SCREENNORMAL to new state */
1533 WorkSpaceLayout *layout_new;
1534 ScrArea *newa;
1535 char newname[MAX_ID_NAME - 2];
1536
1538
1539 bScreen *oldscreen = WM_window_get_active_screen(win);
1540
1541 oldscreen->state = state;
1542 SNPRINTF(newname, "%s-%s", oldscreen->id.name + 2, "nonnormal");
1543
1544 layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
1545
1546 bScreen *screen = BKE_workspace_layout_screen_get(layout_new);
1547 screen->state = state;
1548 screen->redraws_flag = oldscreen->redraws_flag;
1549 screen->temp = oldscreen->temp;
1550 screen->flag = oldscreen->flag;
1551
1552 /* timer */
1553 screen->animtimer = oldscreen->animtimer;
1554 oldscreen->animtimer = nullptr;
1555
1556 newa = (ScrArea *)screen->areabase.first;
1557
1558 /* swap area */
1559 if (toggle_area) {
1560 ED_area_data_swap(newa, toggle_area);
1561 newa->flag = toggle_area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
1562 }
1563
1564 if (state == SCREENFULL) {
1565 /* temporarily hide global areas */
1566 LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
1567 glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
1568 }
1569 /* temporarily hide the side panels/header */
1570 LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) {
1571 region->flagfullscreen = region->flag;
1572
1573 if (ELEM(region->regiontype,
1583 {
1584 region->flag |= RGN_FLAG_HIDDEN;
1585 }
1586 }
1587 }
1588
1589 if (toggle_area) {
1590 toggle_area->full = oldscreen;
1591 }
1592 newa->full = oldscreen;
1593
1594 ED_area_tag_refresh(newa);
1595
1596 return screen;
1597}
1598
1603
1605{
1607 WorkSpace *workspace = WM_window_get_active_workspace(win);
1608
1609 if (area) {
1610 /* ensure we don't have a button active anymore, can crash when
1611 * switching screens with tooltip open because region and tooltip
1612 * are no longer in the same screen */
1613 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1614 UI_blocklist_free(C, region);
1615 if (region->regiontimer) {
1616 WM_event_timer_remove(wm, nullptr, region->regiontimer);
1617 region->regiontimer = nullptr;
1618 }
1619 }
1620
1621 /* prevent hanging status prints */
1622 ED_area_status_text(area, nullptr);
1623 ED_workspace_status_text(C, nullptr);
1624 }
1625 bScreen *screen;
1626 if (area && area->full) {
1628 /* restoring back to SCREENNORMAL */
1629 screen = area->full; /* the old screen to restore */
1630 bScreen *oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
1631
1632 BLI_assert(BKE_workspace_layout_screen_get(layout_old) != screen);
1634
1635 screen->state = SCREENNORMAL;
1636 screen->flag = oldscreen->flag;
1637
1638 /* Find old area we may have swapped dummy space data to. It's swapped back here. */
1639 ScrArea *fullsa = nullptr;
1640 LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) {
1641 /* area to restore from is always first */
1642 if (old->full && !fullsa) {
1643 fullsa = old;
1644 }
1645
1646 /* clear full screen state */
1647 old->full = nullptr;
1648 }
1649
1650 area->full = nullptr;
1651
1652 if (state == SCREENFULL) {
1653 /* unhide global areas */
1654 LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
1655 glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
1656 }
1657 /* restore the old side panels/header visibility */
1658 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1659 region->flag = region->flagfullscreen;
1660 }
1661 }
1662
1663 if (fullsa) {
1664 ED_area_data_swap(fullsa, area);
1665 ED_area_tag_refresh(fullsa);
1666 }
1667
1668 /* animtimer back */
1669 screen->animtimer = oldscreen->animtimer;
1670 oldscreen->animtimer = nullptr;
1671
1672 ED_screen_change(C, screen);
1673
1674 BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
1675
1676 /* After we've restored back to SCREENNORMAL, we have to wait with
1677 * screen handling as it uses the area coords which aren't updated yet.
1678 * Without doing so, the screen handling gets wrong area coords,
1679 * which in worst case can lead to crashes (see #43139) */
1680 screen->skip_handling = true;
1681 }
1682 else {
1683 ScrArea *toggle_area = area;
1684
1685 /* use random area when we have no active one, e.g. when the
1686 * mouse is outside of the window and we open a file browser */
1687 if (!toggle_area || toggle_area->global) {
1688 bScreen *oldscreen = WM_window_get_active_screen(win);
1689 toggle_area = static_cast<ScrArea *>(oldscreen->areabase.first);
1690 }
1691
1692 screen = screen_state_to_nonnormal(C, win, toggle_area, state);
1693
1694 ED_screen_change(C, screen);
1695 }
1696
1697 BLI_assert(CTX_wm_screen(C) == screen);
1698 BLI_assert(CTX_wm_area(C) == nullptr); /* May have been freed. */
1699
1700 /* Setting the area is only needed for Python scripts that call
1701 * operators in succession before returning to the main event loop.
1702 * Without this, scripts can't run any operators that require
1703 * an area after toggling full-screen for example (see: #89526).
1704 * NOTE: an old comment stated this was "bad code",
1705 * however it doesn't cause problems so leave as-is. */
1706 CTX_wm_area_set(C, static_cast<ScrArea *>(screen->areabase.first));
1707
1708 return static_cast<ScrArea *>(screen->areabase.first);
1709}
1710
1712 const char *title,
1713 const rcti *rect_unscaled,
1714 eSpace_Type space_type,
1715 int display_type,
1716 bool dialog)
1717{
1718 ScrArea *area = nullptr;
1719
1720 switch (display_type) {
1722 if (WM_window_open(C,
1723 title,
1724 rect_unscaled,
1725 int(space_type),
1726 false,
1727 dialog,
1728 true,
1730 nullptr,
1731 nullptr))
1732 {
1733 area = CTX_wm_area(C);
1734 }
1735 break;
1737 ScrArea *ctx_area = CTX_wm_area(C);
1738
1739 if (ctx_area != nullptr && ctx_area->full) {
1740 area = ctx_area;
1741 ED_area_newspace(C, ctx_area, space_type, true);
1742 area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
1743 ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
1744 }
1745 else {
1746 area = ED_screen_full_newspace(C, ctx_area, int(space_type));
1747 ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
1748 }
1749 break;
1750 }
1751 }
1752
1753 return area;
1754}
1755
1756void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
1757{
1758 bScreen *screen = CTX_wm_screen(C);
1760 wmWindow *win = CTX_wm_window(C);
1761 Scene *scene = CTX_data_scene(C);
1762 bScreen *stopscreen = ED_screen_animation_playing(wm);
1763
1764 if (stopscreen) {
1765 WM_event_timer_remove(wm, win, stopscreen->animtimer);
1766 stopscreen->animtimer = nullptr;
1767 }
1768
1769 if (enable) {
1770 ScreenAnimData *sad = static_cast<ScreenAnimData *>(
1771 MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData"));
1772
1773 screen->animtimer = WM_event_timer_add(wm, win, TIMER0, (1.0 / FPS));
1774
1775 sad->region = CTX_wm_region(C);
1776 /* If start-frame is larger than current frame, we put current-frame on start-frame.
1777 * NOTE(ton): first frame then is not drawn! */
1778 if (PRVRANGEON) {
1779 if (scene->r.psfra > scene->r.cfra) {
1780 sad->sfra = scene->r.cfra;
1781 scene->r.cfra = scene->r.psfra;
1782 }
1783 else {
1784 sad->sfra = scene->r.cfra;
1785 }
1786 }
1787 else {
1788 if (scene->r.sfra > scene->r.cfra) {
1789 sad->sfra = scene->r.cfra;
1790 scene->r.cfra = scene->r.sfra;
1791 }
1792 else {
1793 sad->sfra = scene->r.cfra;
1794 }
1795 }
1796 sad->redraws = redraws;
1797 sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
1798 sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
1799
1800 ScrArea *area = CTX_wm_area(C);
1801
1802 char spacetype = -1;
1803
1804 if (area) {
1805 spacetype = area->spacetype;
1806 }
1807
1809
1810 screen->animtimer->customdata = sad;
1811
1812 /* Seek audio to ensure playback in preview range with AV sync. */
1814 }
1815
1816 /* Notifier caught by top header, for button. */
1818}
1819
1820/* helper for screen_animation_play() - only to be used for TimeLine */
1822{
1823 ARegion *region_top_left = nullptr;
1824 int min = 10000;
1825
1826 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1827 if (area->spacetype == SPACE_VIEW3D) {
1828 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1829 if (region->regiontype == RGN_TYPE_WINDOW) {
1830 if (region->winrct.xmin - region->winrct.ymin < min) {
1831 region_top_left = region;
1832 min = region->winrct.xmin - region->winrct.ymin;
1833 }
1834 }
1835 }
1836 }
1837 }
1838
1839 return region_top_left;
1840}
1841
1843{
1844 if (screen && screen->animtimer) {
1845 wmTimer *wt = screen->animtimer;
1846 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
1847
1848 sad->redraws = redraws;
1849 sad->region = nullptr;
1850 if (redraws & TIME_REGION) {
1851 sad->region = time_top_left_3dwindow(screen);
1852 }
1853 }
1854}
1855
1856void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
1857{
1859
1860 DEG_time_tag_update(bmain);
1861
1862#ifdef DURIAN_CAMERA_SWITCH
1863 void *camera = BKE_scene_camera_switch_find(scene);
1864 if (camera && scene->camera != camera) {
1865 scene->camera = static_cast<Object *>(camera);
1866 /* are there cameras in the views that are not in the scene? */
1867 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
1868 BKE_screen_view3d_scene_sync(screen, scene);
1869 }
1871 }
1872#endif
1873
1874 ED_clip_update_frame(bmain, scene->r.cfra);
1875
1876 /* this function applies the changes too */
1878}
1879
1880bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
1881{
1882 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
1883
1884 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1885 switch (area->spacetype) {
1886 case SPACE_VIEW3D: {
1887 View3D *v3d;
1888
1889 if (!is_multiview) {
1890 continue;
1891 }
1892
1893 v3d = static_cast<View3D *>(area->spacedata.first);
1894 if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
1895 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1896 if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
1897 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1898 if (rv3d->persp == RV3D_CAMOB) {
1899 return true;
1900 }
1901 }
1902 }
1903 }
1904 break;
1905 }
1906 case SPACE_IMAGE: {
1907 SpaceImage *sima;
1908
1909 /* images should always show in stereo, even if
1910 * the file doesn't have views enabled */
1911 sima = static_cast<SpaceImage *>(area->spacedata.first);
1912 if (sima->image && BKE_image_is_stereo(sima->image) &&
1913 (sima->iuser.flag & IMA_SHOW_STEREO))
1914 {
1915 return true;
1916 }
1917 break;
1918 }
1919 case SPACE_NODE: {
1920 SpaceNode *snode;
1921
1922 if (!is_multiview) {
1923 continue;
1924 }
1925
1926 snode = static_cast<SpaceNode *>(area->spacedata.first);
1927 if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
1928 return true;
1929 }
1930 break;
1931 }
1932 case SPACE_SEQ: {
1933 SpaceSeq *sseq;
1934
1935 if (!is_multiview) {
1936 continue;
1937 }
1938
1939 sseq = static_cast<SpaceSeq *>(area->spacedata.first);
1941 return true;
1942 }
1943
1944 if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
1945 return true;
1946 }
1947
1948 break;
1949 }
1950 }
1951 }
1952
1953 return false;
1954}
1955
1957 const wmWindowManager *wm,
1958 wmWindow **r_window)
1959{
1960 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1961 if (WM_window_get_active_screen(win) == screen) {
1962 if (r_window) {
1963 *r_window = win;
1964 }
1965 return WM_window_get_active_scene(win);
1966 }
1967 }
1968
1969 /* Can by nullptr when accessing a screen that isn't active. */
1970 return nullptr;
1971}
1972
1974 const SpaceLink *sl,
1975 const bool only_visible)
1976{
1977 if (only_visible) {
1978 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1979 if (area->spacedata.first == sl) {
1980 return area;
1981 }
1982 }
1983 }
1984 else {
1985 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1986 if (BLI_findindex(&area->spacedata, sl) != -1) {
1987 return area;
1988 }
1989 }
1990 }
1991 return nullptr;
1992}
1993
1995{
1996 return ED_screen_scene_find_with_window(screen, wm, nullptr);
1997}
1998
2000{
2001 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2002 if (WM_window_get_active_screen(win) == screen) {
2003 return win;
2004 }
2005 }
2006 return nullptr;
2007}
WorkSpace * CTX_wm_workspace(const bContext *C)
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
void CTX_data_scene_set(bContext *C, Scene *scene)
Scene * CTX_data_scene(const bContext *C)
void CTX_wm_window_set(bContext *C, wmWindow *win)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
@ G_DEBUG_EVENTS
void BKE_icon_changed(int icon_id)
Definition icons.cc:205
bool BKE_image_is_stereo(const Image *ima)
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_camera_find(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1415
void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph)
Definition scene.cc:2647
void BKE_screen_remove_unused_scredges(bScreen *screen)
Definition screen.cc:734
void BKE_screen_remove_double_scrverts(bScreen *screen)
Definition screen.cc:666
void BKE_screen_sort_scrvert(ScrVert **v1, ScrVert **v2)
Definition screen.cc:657
void BKE_screen_area_free(ScrArea *area)
Definition screen.cc:607
void BKE_screen_area_map_free(ScrAreaMap *area_map) ATTR_NONNULL()
Definition screen.cc:623
SpaceType * BKE_spacetype_from_id(int spaceid)
Definition screen.cc:243
void BKE_screen_header_alignment_reset(bScreen *screen)
Definition screen.cc:1018
void BKE_area_region_free(SpaceType *st, ARegion *region)
Definition screen.cc:563
void BKE_screen_view3d_scene_sync(bScreen *screen, Scene *scene)
Definition screen.cc:963
void BKE_screen_remove_double_scredges(bScreen *screen)
Definition screen.cc:718
void BKE_screen_view3d_sync(View3D *v3d, Scene *scene)
Definition screen.cc:945
void BKE_screen_free_data(bScreen *screen)
Definition screen.cc:634
void BKE_sound_stop_scene(struct Scene *scene)
WorkSpaceLayout * BKE_workspace_layout_find(const WorkSpace *workspace, const bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
Definition workspace.cc:427
bScreen * BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout) GETTER_ATTRS
Definition workspace.cc:638
void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout) ATTR_NONNULL()
Definition workspace.cc:397
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:562
void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) SETTER_ATTRS
Definition workspace.cc:566
#define BLI_assert(a)
Definition BLI_assert.h:50
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:90
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
void void void void void void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
#define UNUSED_VARS(...)
#define UNUSED_VARS_NDEBUG(...)
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_time_tag_update(Main *bmain)
Scene * DEG_get_input_scene(const Depsgraph *graph)
ID * DEG_get_evaluated_id(const Depsgraph *depsgraph, ID *id)
@ ID_RECALC_FRAME_CHANGE
Definition DNA_ID.h:1092
@ ID_RECALC_SYNC_TO_EVAL
Definition DNA_ID.h:1085
#define MAX_ID_NAME
Definition DNA_ID.h:377
@ ID_SCR
@ IMA_SHOW_STEREO
eObjectMode
Object is a sort of wrapper for general info.
@ R_MULTIVIEW
@ STEREO_3D_ID
#define FPS
#define PRVRANGEON
@ SCREENFULL
@ SCREENMAXIMIZED
@ SCREENNORMAL
@ AREA_FLAG_STACKED_FULLSCREEN
#define AREAMAP_FROM_SCREEN(screen)
@ GLOBAL_AREA_IS_HIDDEN
@ RGN_TYPE_TOOL_HEADER
@ RGN_TYPE_EXECUTE
@ RGN_TYPE_UI
@ RGN_TYPE_TEMPORARY
@ RGN_TYPE_ASSET_SHELF_HEADER
@ RGN_TYPE_WINDOW
@ RGN_TYPE_ASSET_SHELF
@ RGN_TYPE_NAV_BAR
@ RGN_TYPE_FOOTER
@ RGN_TYPE_HEADER
@ RGN_TYPE_TOOLS
@ SCREEN_COLLAPSE_STATUSBAR
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_POLL_FAILED
@ TIME_REGION
@ TIME_ALL_3D_WIN
@ TIME_ALL_ANIM_WIN
GlobalAreaAlign
@ GLOBAL_AREA_ALIGN_BOTTOM
@ GLOBAL_AREA_ALIGN_TOP
@ SNODE_BACKDRAW
eSpace_Type
@ SPACE_ACTION
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SEQ_VIEW_SEQUENCE_PREVIEW
@ SEQ_VIEW_PREVIEW
@ SEQ_DRAW_BACKDROP
@ SPACE_FLAG_TYPE_WAS_ACTIVE
@ SPACE_FLAG_TYPE_TEMPORARY
@ USER_HEADER_FROM_PREF
#define UI_SCALE_FAC
@ USER_TEMP_SPACE_DISPLAY_FULLSCREEN
@ USER_TEMP_SPACE_DISPLAY_WINDOW
@ RV3D_CAMOB
@ RV3D_PERSP
void ED_clip_update_frame(const Main *mainp, int cfra)
bool ED_node_is_compositor(const SpaceNode *snode)
Definition node_edit.cc:523
void ED_area_tag_redraw(ScrArea *area)
Definition area.cc:708
void ED_area_newspace(bContext *C, ScrArea *area, int type, bool skip_region_exit)
Definition area.cc:2592
WorkSpaceLayout * ED_workspace_layout_add(Main *bmain, WorkSpace *workspace, wmWindow *win, const char *name) ATTR_NONNULL()
void ED_region_cursor_set(wmWindow *win, ScrArea *area, ARegion *region)
Definition area.cc:2216
#define ED_screen_verts_iter(win, screen, vert_name)
Definition ED_screen.hh:284
bool ED_region_contains_xy(const ARegion *region, const int event_xy[2])
#define ED_screen_areas_iter(win, screen, area_name)
Definition ED_screen.hh:281
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:803
void ED_region_tag_redraw_no_rebuild(ARegion *region)
Definition area.cc:653
int ED_area_headersize()
Definition area.cc:3666
WorkSpaceLayout * ED_workspace_screen_change_ensure_unused_layout(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout_new, const WorkSpaceLayout *layout_fallback_base, wmWindow *win) ATTR_NONNULL()
void ED_region_visibility_change_update(bContext *C, ScrArea *area, ARegion *region)
Definition area.cc:2254
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_area_tag_refresh(ScrArea *area)
Definition area.cc:737
AZone * ED_area_azones_update(ScrArea *area, const int mouse_xy[2])
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:966
void ED_area_prevspace(bContext *C, ScrArea *area)
Definition area.cc:2742
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2036
@ ANIMPLAY_FLAG_NO_SYNC
@ ANIMPLAY_FLAG_REVERSE
@ ANIMPLAY_FLAG_SYNC
@ AZONE_REGION
@ AZONE_REGION_SCROLL
@ AZONE_AREA
@ AE_LEFT_TO_TOPRIGHT
@ AE_RIGHT_TO_TOPLEFT
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between camera
#define C
Definition RandGen.cpp:29
void UI_blocklist_free(const bContext *C, ARegion *region)
void UI_screen_free_active_but_highlight(const bContext *C, bScreen *screen)
@ WIN_ALIGN_LOCATION_CENTER
Definition WM_api.hh:340
#define NC_WINDOW
Definition WM_types.hh:342
#define ND_FILEREAD
Definition WM_types.hh:379
#define NC_WM
Definition WM_types.hh:341
#define NC_SCREEN
Definition WM_types.hh:344
#define ND_MODE
Definition WM_types.hh:412
#define ND_ANIMPLAY
Definition WM_types.hh:391
#define NC_SCENE
Definition WM_types.hh:345
#define NA_EDITED
Definition WM_types.hh:550
#define ND_LAYOUTSET
Definition WM_types.hh:393
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition area.cc:2281
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src)
Definition area.cc:2314
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
unsigned int U
Definition btGjkEpa3.h:78
#define printf
const Depsgraph * depsgraph
#define ceilf(x)
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds &cone_b)
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
static ulong state[N]
#define G(x, y, z)
int RNA_enum_from_value(const EnumPropertyItem *item, const int value)
const EnumPropertyItem rna_enum_space_type_items[]
Definition rna_space.cc:97
int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result)
int ED_area_icon(const ScrArea *area)
void ED_screen_global_areas_sync(wmWindow *win)
static bool screen_areas_can_align(bScreen *screen, ScrArea *sa1, ScrArea *sa2, eScreenDir dir)
static ScrArea * screen_addarea_ex(ScrAreaMap *area_map, ScrVert *bottom_left, ScrVert *top_left, ScrVert *top_right, ScrVert *bottom_right, const eSpace_Type space_type)
int ED_screen_area_active(const bContext *C)
bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
wmWindow * ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm)
static void screen_global_area_refresh(wmWindow *win, bScreen *screen, const eSpace_Type space_type, GlobalAreaAlign align, const rcti *rect, const short height_cur, const short height_min, const short height_max)
static void screen_set_3dview_camera(Scene *scene, ViewLayer *view_layer, ScrArea *area, View3D *v3d)
Scene * ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
void screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
static void screen_refresh(bContext *C, wmWindowManager *wm, wmWindow *win, const bool force_full_refresh)
static ScrArea * screen_area_create_with_geometry(ScrAreaMap *area_map, const rcti *rect, eSpace_Type space_type)
void ED_screen_ensure_updated(bContext *C, wmWindowManager *wm, wmWindow *win)
void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
ScrArea * ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state)
ScrArea * ED_screen_area_find_with_spacedata(const bScreen *screen, const SpaceLink *sl, const bool only_visible)
void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2)
static void region_cursor_set(wmWindow *win, bool swin_changed)
void ED_screen_refresh(bContext *C, wmWindowManager *wm, wmWindow *win)
void ED_screen_full_restore(bContext *C, ScrArea *area)
static void screen_verts_halign(const wmWindow *win, const bScreen *screen, const short from_x, const short to_x)
static bool region_poll(const bContext *C, const bScreen *screen, const ScrArea *area, const ARegion *region)
eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b)
ScrArea * ED_screen_full_newspace(bContext *C, ScrArea *area, int type)
static void screen_global_statusbar_area_refresh(wmWindow *win, bScreen *screen)
int screen_area_join(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
void ED_screen_do_listen(bContext *C, const wmNotifier *note)
void ED_screens_init(bContext *C, Main *bmain, wmWindowManager *wm)
static bool screen_area_join_ex(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, bool close_all_remainders)
static void screen_delarea(bContext *C, bScreen *screen, ScrArea *area)
void ED_screen_global_areas_refresh(wmWindow *win)
bool ED_screen_change(bContext *C, bScreen *screen)
Change the active screen.
bScreen * ED_screen_state_maximized_create(bContext *C)
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
void ED_screen_restore_temp_type(bContext *C, ScrArea *area)
ScrArea * area_split(const wmWindow *win, bScreen *screen, ScrArea *area, const eScreenAxis dir_axis, const float fac, const bool merge)
static bool screen_area_join_aligned(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2)
void screen_change_update(bContext *C, wmWindow *win, bScreen *screen)
static void screen_verts_valign(const wmWindow *win, const bScreen *screen, const short from_y, const short to_y)
void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
bool screen_area_close(bContext *C, bScreen *screen, ScrArea *area)
void ED_area_exit(bContext *C, ScrArea *area)
static ScrArea * screen_addarea(bScreen *screen, ScrVert *left_bottom, ScrVert *left_top, ScrVert *right_top, ScrVert *right_bottom, const eSpace_Type space_type)
static void screen_global_topbar_area_refresh(wmWindow *win, bScreen *screen)
ScrArea * ED_screen_temp_space_open(bContext *C, const char *title, const rcti *rect_unscaled, eSpace_Type space_type, int display_type, bool dialog)
static bScreen * screen_state_to_nonnormal(bContext *C, wmWindow *win, ScrArea *toggle_area, int state)
void ED_screen_animation_timer_update(bScreen *screen, int redraws)
void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
blender::StringRefNull ED_area_name(const ScrArea *area)
static bool screen_areas_align(bContext *C, bScreen *screen, ScrArea *sa1, ScrArea *sa2, const eScreenDir dir)
void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
static void screen_cursor_set(wmWindow *win, const int xy[2])
void screen_data_copy(bScreen *to, bScreen *from)
static bool screen_regions_poll(bContext *C, wmWindow *win, const bScreen *screen)
void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene, const bool refresh_toolsystem)
static ScrArea * screen_area_trim(bContext *C, bScreen *screen, ScrArea **area, int size, eScreenDir dir, bool reverse)
static ARegion * time_top_left_3dwindow(bScreen *screen)
void ED_region_remove(bContext *C, ScrArea *area, ARegion *region)
static int screen_global_header_size()
bScreen * screen_add(Main *bmain, const char *name, const rcti *rect)
void ED_region_exit(bContext *C, ARegion *region)
static void region_cursor_set_ex(wmWindow *win, ScrArea *area, ARegion *region, bool swin_changed)
void ED_screen_full_prevspace(bContext *C, ScrArea *area)
Scene * ED_screen_scene_find_with_window(const bScreen *screen, const wmWindowManager *wm, wmWindow **r_window)
void screen_area_spacelink_add(const Scene *scene, ScrArea *area, eSpace_Type space_type)
ScrVert * screen_geom_vertex_add(bScreen *screen, short x, short y)
ScrEdge * screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
ScrVert * screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y)
ScrEdge * screen_geom_find_active_scredge(const wmWindow *win, const bScreen *screen, const int mx, const int my)
ScrEdge * screen_geom_edge_add(bScreen *screen, ScrVert *v1, ScrVert *v2)
bool screen_geom_edge_is_horizontal(ScrEdge *se)
void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen)
Main screen-layout calculation function.
short screen_geom_find_area_split_point(const ScrArea *area, const rcti *window_rect, const eScreenAxis dir_axis, float fac)
#define SCREEN_DIR_IS_HORIZONTAL(dir)
#define BORDERPADDING
AZone * ED_area_actionzone_find_xy(ScrArea *area, const int xy[2])
eScreenAxis
@ SCREEN_AXIS_V
@ SCREEN_AXIS_H
#define SCREEN_DIR_IS_VERTICAL(dir)
#define AREAJOINTOLERANCEX
eScreenDir
@ SCREEN_DIR_W
@ SCREEN_DIR_N
@ SCREEN_DIR_E
@ SCREEN_DIR_S
@ SCREEN_DIR_NONE
#define AREAJOINTOLERANCEY
#define min(a, b)
Definition sort.c:32
struct wmGizmoMap * gizmo_map
struct ARegionType * type
AZEdge edge
const char * name
Definition RNA_types.hh:510
char name[66]
Definition DNA_ID.h:425
void * first
ListBase screens
Definition BKE_main.hh:225
ListBase workspaces
Definition BKE_main.hh:246
ListBase areabase
ScrVert * v2
ScrVert * v3
ListBase spacedata
bScreen * full
ScrVert * v1
struct ScrArea * next
ListBase regionbase
ScrGlobalAreaData * global
ScrVert * v4
struct ScrVert * next
struct ScrVert * newv
struct ImageUser iuser
struct Image * image
SpaceLink *(* create)(const ScrArea *area, const Scene *scene)
Definition BKE_screen.hh:82
struct Object * camera
char stereo3d_camera
ListBase regionbase
Wrapper for bScreen.
short redraws_flag
struct wmTimer * animtimer
ListBase areabase
int ymin
int ymax
int xmin
int xmax
short y
short x
int xy[2]
Definition WM_types.hh:726
unsigned int data
Definition WM_types.hh:325
unsigned int action
Definition WM_types.hh:325
unsigned int category
Definition WM_types.hh:325
void * customdata
Definition WM_types.hh:922
struct wmMsgBus * message_bus
struct wmWindow * parent
struct wmEvent * eventstate
struct Scene * scene
ScrAreaMap global_areas
struct WorkSpaceInstanceHook * workspace_hook
ccl_device_inline int abs(int x)
Definition util/math.h:120
void WM_cursor_set(wmWindow *win, int curs)
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
@ WM_CURSOR_Y_MOVE
Definition wm_cursors.hh:39
@ WM_CURSOR_EDIT
Definition wm_cursors.hh:19
@ WM_CURSOR_X_MOVE
Definition wm_cursors.hh:38
int xy[2]
Definition wm_draw.cc:170
void WM_draw_region_free(ARegion *region)
Definition wm_draw.cc:1603
bool WM_cursor_test_motion_and_update(const int mval[2])
void WM_window_status_area_tag_redraw(wmWindow *win)
void WM_event_remove_area_handler(ListBase *handlers, void *area)
void WM_report(eReportType type, const char *message)
void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void WM_event_ui_handler_region_popup_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
void WM_event_add_mousemove(wmWindow *win)
@ TIMER0
bool WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
Definition wm_gizmo.cc:401
void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner)
void WM_toolsystem_refresh_screen_window(wmWindow *win)
blender::int2 WM_window_native_pixel_size(const wmWindow *win)
void WM_window_ensure_active_view_layer(wmWindow *win)
WorkSpaceLayout * WM_window_get_active_layout(const wmWindow *win)
void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *, wmTimer *timer, bool do_sleep)
void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
void WM_window_set_dpi(const wmWindow *win)
Definition wm_window.cc:552
wmWindow * WM_window_open(bContext *C, const char *title, const rcti *rect_unscaled, int space_type, bool toplevel, bool dialog, bool temp, eWindowAlignment alignment, void(*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data), void *area_setup_user_data)
Definition wm_window.cc:950
bool WM_window_is_temp_screen(const wmWindow *win)
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)
bScreen * WM_window_get_active_screen(const wmWindow *win)