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
8
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;
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);
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 else {
558 /* Force full rebuild. #130732 */
559 ED_area_tag_redraw(side1);
560 ED_area_tag_redraw(side2);
561 }
562
563 BKE_icon_changed(screen->id.icon_id);
564 return true;
565}
566
568{
569 return screen_area_join_ex(C, screen, sa1, sa2, false);
570}
571
573{
574 if (area == nullptr) {
575 return false;
576 }
577
578 ScrArea *sa2 = nullptr;
579 float best_alignment = 0.0f;
580
581 LISTBASE_FOREACH (ScrArea *, neighbor, &screen->areabase) {
582 const eScreenDir dir = area_getorientation(area, neighbor);
583 /* Must at least partially share an edge and not be a global area. */
584 if ((dir != SCREEN_DIR_NONE) && (neighbor->global == nullptr)) {
585 /* Winx/Winy might not be updated yet, so get lengths from verts. */
586 const bool vertical = SCREEN_DIR_IS_VERTICAL(dir);
587 const int area_length = vertical ? (area->v3->vec.x - area->v1->vec.x) :
588 (area->v3->vec.y - area->v1->vec.y);
589 const int ar_length = vertical ? (neighbor->v3->vec.x - neighbor->v1->vec.x) :
590 (neighbor->v3->vec.y - neighbor->v1->vec.y);
591 /* Calculate the ratio of the lengths of the shared edges. */
592 float alignment = std::min(area_length, ar_length) / float(std::max(area_length, ar_length));
593 if (alignment > best_alignment) {
594 best_alignment = alignment;
595 sa2 = neighbor;
596 }
597 }
598 }
599
600 /* Join from neighbor into this area to close it. */
601 return screen_area_join_ex(C, screen, sa2, area, true);
602}
603
604void screen_area_spacelink_add(const Scene *scene, ScrArea *area, eSpace_Type space_type)
605{
606 SpaceType *stype = BKE_spacetype_from_id(space_type);
607 SpaceLink *slink = stype->create(area, scene);
608
609 area->regionbase = slink->regionbase;
610
611 BLI_addhead(&area->spacedata, slink);
613}
614
615/* ****************** EXPORTED API TO OTHER MODULES *************************** */
616
617/* screen sets cursor based on active region */
618static void region_cursor_set_ex(wmWindow *win, ScrArea *area, ARegion *region, bool swin_changed)
619{
620 BLI_assert(WM_window_get_active_screen(win)->active_region == region);
621 if (win->tag_cursor_refresh || swin_changed || (region->type && region->type->event_cursor)) {
622 win->tag_cursor_refresh = false;
623 ED_region_cursor_set(win, area, region);
624 }
625}
626
627static void region_cursor_set(wmWindow *win, bool swin_changed)
628{
630
631 ED_screen_areas_iter (win, screen, area) {
632 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
633 if (region == screen->active_region) {
634 region_cursor_set_ex(win, area, region, swin_changed);
635 return;
636 }
637 }
638 }
639}
640
642{
643 wmWindow *win = CTX_wm_window(C);
644 bScreen *screen = CTX_wm_screen(C);
645
646 /* generic notes */
647 switch (note->category) {
648 case NC_WM:
649 if (note->data == ND_FILEREAD) {
650 screen->do_draw = true;
651 }
652 break;
653 case NC_WINDOW:
654 screen->do_draw = true;
655 break;
656 case NC_SCREEN:
657 if (note->action == NA_EDITED) {
658 screen->do_draw = screen->do_refresh = true;
659 }
660 break;
661 case NC_SCENE:
662 if (note->data == ND_MODE) {
663 region_cursor_set(win, true);
664 }
665 break;
666 }
667}
668
669static bool region_poll(const bContext *C,
670 const bScreen *screen,
671 const ScrArea *area,
672 const ARegion *region)
673{
674 if (!region->type) {
676 return false;
677 }
678 if (!region->type->poll) {
679 /* Show region by default. */
680 return true;
681 }
682
683 RegionPollParams params = {nullptr};
684 params.screen = screen;
685 params.area = area;
686 params.region = region;
687 params.context = C;
688
689 return region->type->poll(&params);
690}
691
695static bool screen_regions_poll(bContext *C, wmWindow *win, const bScreen *screen)
696{
697 wmWindow *prev_win = CTX_wm_window(C);
698 ScrArea *prev_area = CTX_wm_area(C);
699 ARegion *prev_region = CTX_wm_region(C);
700
701 CTX_wm_window_set(C, win);
702
703 bool any_changed = false;
704 ED_screen_areas_iter (win, screen, area) {
705 CTX_wm_area_set(C, area);
706
707 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
708 const int old_region_flag = region->flag;
709
710 region->flag &= ~RGN_FLAG_POLL_FAILED;
711
712 CTX_wm_region_set(C, region);
713 if (region_poll(C, screen, area, region) == false) {
714 region->flag |= RGN_FLAG_POLL_FAILED;
715 }
716 else if (region->type && region->type->on_poll_success) {
717 region->type->on_poll_success(C, region);
718 }
719
720 if (old_region_flag != region->flag) {
721 any_changed = true;
722
723 /* Enforce complete re-init. */
724 region->v2d.flag &= ~V2D_IS_INIT;
726 }
727 }
728 }
729
730 CTX_wm_window_set(C, prev_win);
731 CTX_wm_area_set(C, prev_area);
732 CTX_wm_region_set(C, prev_region);
733
734 return any_changed;
735}
736
742 wmWindowManager *wm,
743 wmWindow *win,
744 const bool force_full_refresh)
745{
747 bool do_refresh = screen->do_refresh;
748
749 /* Exception for background mode, we only need the screen context. */
750 if (!G.background) {
751 if (do_refresh || force_full_refresh) {
752 ED_screen_areas_iter (win, screen, area) {
753 /* Set area and region types early so areas and regions are in a usable state. This may be
754 * needed by further (re-)initialization logic, specifically region polling needs it early
755 * on (see #130583). */
757 }
758 }
759
760 /* Returns true if a change was done that requires refreshing. */
761 if (screen_regions_poll(C, win, screen)) {
762 do_refresh = true;
763 }
764
765 if (!force_full_refresh && !do_refresh) {
766 return;
767 }
768
769 /* Called even when creating the ghost window fails in #WM_window_open. */
770 if (win->ghostwin) {
771 /* Header size depends on DPI, let's verify. */
773 }
774
776
777 screen_geom_vertices_scale(win, screen);
778
779 ED_screen_areas_iter (win, screen, area) {
780 /* Set space-type and region callbacks, calls init() */
781 /* Sets sub-windows for regions, adds handlers. */
782 ED_area_init(wm, win, area);
783 }
784
785 /* wake up animtimer */
786 if (screen->animtimer) {
787 WM_event_timer_sleep(wm, win, screen->animtimer, false);
788 }
789 }
790
791 if (G.debug & G_DEBUG_EVENTS) {
792 printf("%s: set screen\n", __func__);
793 }
794 screen->do_refresh = false;
795 /* Prevent multi-window errors. */
796 screen->winid = win->winid;
797
798 screen->context = reinterpret_cast<void *>(ed_screen_context);
799}
800
802{
803 screen_refresh(C, wm, win, /*force_full_refresh=*/true);
804}
805
807{
808 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
809 if (BKE_workspace_active_get(win->workspace_hook) == nullptr) {
810 BKE_workspace_active_set(win->workspace_hook,
811 static_cast<WorkSpace *>(bmain->workspaces.first));
812 }
813
814 ED_screen_refresh(C, wm, win);
815 if (win->eventstate) {
816 ED_screen_set_active_region(nullptr, win, win->eventstate->xy);
817 }
818 }
819
820 if (U.uiflag & USER_HEADER_FROM_PREF) {
821 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
823 }
824 }
825}
826
828{
829 /* Only do a full refresh if required (checks #bScreen.do_refresh tag). */
830 const bool force_full_refresh = false;
831 screen_refresh(C, wm, win, force_full_refresh);
832}
833
835{
836 ED_region_exit(C, region);
837 BKE_area_region_free(area->type, region);
838 BLI_freelinkN(&area->regionbase, region);
839}
840
841/* *********** exit calls are for closing running stuff ******** */
842
844{
846 wmWindow *win = CTX_wm_window(C);
847 ARegion *prevar = CTX_wm_region(C);
848
849 if (region->type && region->type->exit) {
850 region->type->exit(wm, region);
851 }
852
853 CTX_wm_region_set(C, region);
854
856 WM_event_modal_handler_region_replace(win, region, nullptr);
857
858 if (region->regiontype == RGN_TYPE_TEMPORARY) {
859 /* This may be a popup region such as a popover or splash screen.
860 * In the case of popups which spawn popups it's possible for
861 * the parent popup to be freed *before* a popup which created it.
862 * The child may have a reference to the freed parent unless cleared here, see: #122132.
863 *
864 * Having parent popups freed before the popups they spawn could be investigated although
865 * they're not technically nested as they're both stored in #Screen::regionbase. */
866 WM_event_ui_handler_region_popup_replace(win, region, nullptr);
867 }
868
869 WM_draw_region_free(region);
870 /* The region is not in a state that it can be visible in anymore. Reinitializing is needed. */
871 region->visible = false;
872
873 MEM_SAFE_FREE(region->headerstr);
874
875 if (region->regiontimer) {
876 WM_event_timer_remove(wm, win, region->regiontimer);
877 region->regiontimer = nullptr;
878 }
879
881
882 CTX_wm_region_set(C, prevar);
883}
884
886{
888 wmWindow *win = CTX_wm_window(C);
889 ScrArea *prevsa = CTX_wm_area(C);
890
891 if (area->type && area->type->exit) {
892 area->type->exit(wm, area);
893 }
894
895 CTX_wm_area_set(C, area);
896
897 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
898 ED_region_exit(C, region);
899 }
900
902 WM_event_modal_handler_area_replace(win, area, nullptr);
903
904 CTX_wm_area_set(C, prevsa);
905}
906
907void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
908{
910 wmWindow *prevwin = CTX_wm_window(C);
911
912 CTX_wm_window_set(C, window);
913
914 if (screen->animtimer) {
915 WM_event_timer_remove(wm, window, screen->animtimer);
916
918 Scene *scene = WM_window_get_active_scene(prevwin);
919 Scene *scene_eval = (Scene *)DEG_get_evaluated_id(depsgraph, &scene->id);
920 BKE_sound_stop_scene(scene_eval);
921 }
922 screen->animtimer = nullptr;
923 screen->scrubbing = false;
924
925 screen->active_region = nullptr;
926
927 LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) {
928 ED_region_exit(C, region);
929 }
930 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
931 ED_area_exit(C, area);
932 }
933 /* Don't use ED_screen_areas_iter here, it skips hidden areas. */
934 LISTBASE_FOREACH (ScrArea *, area, &window->global_areas.areabase) {
935 ED_area_exit(C, area);
936 }
937
938 /* mark it available for use for other windows */
939 screen->winid = 0;
940
941 if (!WM_window_is_temp_screen(prevwin)) {
942 /* use previous window if possible */
943 CTX_wm_window_set(C, prevwin);
944 }
945 else {
946 /* none otherwise */
947 CTX_wm_window_set(C, nullptr);
948 }
949}
950
952{
953 if (area->type && area->type->space_name_get) {
954 return area->type->space_name_get(area);
955 }
956
959 return item.name;
960}
961
962int ED_area_icon(const ScrArea *area)
963{
964 if (area->type && area->type->space_icon_get) {
965 return area->type->space_icon_get(area);
966 }
967
970 return item.icon;
971}
972
973/* *********************************** */
974
975/* case when on area-edge or in azones, or outside window */
976static void screen_cursor_set(wmWindow *win, const int xy[2])
977{
978 const bScreen *screen = WM_window_get_active_screen(win);
979 AZone *az = nullptr;
980 ScrArea *area = nullptr;
981
982 LISTBASE_FOREACH (ScrArea *, area_iter, &screen->areabase) {
983 az = ED_area_actionzone_find_xy(area_iter, xy);
984 /* Scrollers use default cursor and their zones extend outside of their
985 * areas. Ignore here so we can always detect screen edges - #110085. */
986 if (az && az->type != AZONE_REGION_SCROLL) {
987 area = area_iter;
988 break;
989 }
990 }
991
992 if (area) {
993 if (az->type == AZONE_AREA) {
995 }
996 else if (az->type == AZONE_REGION) {
999 }
1000 else {
1002 }
1003 }
1004 }
1005 else {
1006 ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, xy[0], xy[1]);
1007
1008 if (actedge) {
1009 if (screen_geom_edge_is_horizontal(actedge)) {
1011 }
1012 else {
1014 }
1015 }
1016 else {
1018 }
1019 }
1020}
1021
1023{
1024 bScreen *screen = WM_window_get_active_screen(win);
1025 if (screen == nullptr) {
1026 return;
1027 }
1028
1029 ScrArea *area = nullptr;
1030 ARegion *region_prev = screen->active_region;
1031
1032 ED_screen_areas_iter (win, screen, area_iter) {
1033 if (xy[0] > (area_iter->totrct.xmin + BORDERPADDING) &&
1034 xy[0] < (area_iter->totrct.xmax - BORDERPADDING))
1035 {
1036 if (xy[1] > (area_iter->totrct.ymin + BORDERPADDING) &&
1037 xy[1] < (area_iter->totrct.ymax - BORDERPADDING))
1038 {
1039 if (ED_area_azones_update(area_iter, xy) == nullptr) {
1040 area = area_iter;
1041 break;
1042 }
1043 }
1044 }
1045 }
1046 if (area) {
1047 /* Make overlap active when mouse over. */
1048 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1049 if (ED_region_contains_xy(region, xy)) {
1050 screen->active_region = region;
1051 break;
1052 }
1053 }
1054 }
1055 else {
1056 screen->active_region = nullptr;
1057 }
1058
1059 if (region_prev != screen->active_region || !screen->active_region) {
1061 }
1062
1063 /* Check for redraw headers. */
1064 if (region_prev != screen->active_region) {
1065
1066 ED_screen_areas_iter (win, screen, area_iter) {
1067 bool do_draw = false;
1068
1069 LISTBASE_FOREACH (ARegion *, region, &area_iter->regionbase) {
1070 /* Call old area's deactivate if assigned. */
1071 if (region == region_prev && area_iter->type && area_iter->type->deactivate) {
1072 area_iter->type->deactivate(area_iter);
1073 }
1074
1075 if (region == region_prev && region != screen->active_region) {
1076 wmGizmoMap *gzmap = region_prev->gizmo_map;
1077 if (gzmap) {
1078 if (WM_gizmo_highlight_set(gzmap, nullptr)) {
1080 }
1081 }
1082 }
1083
1084 if (ELEM(region, region_prev, screen->active_region)) {
1085 do_draw = true;
1086 }
1087 }
1088
1089 if (do_draw) {
1090 LISTBASE_FOREACH (ARegion *, region, &area_iter->regionbase) {
1091 if (ELEM(region->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
1093 }
1094 }
1095 }
1096 }
1097
1098 /* Ensure test-motion values are never shared between regions. */
1099 const int mval[2] = {-1, -1};
1100 const bool use_cycle = !WM_cursor_test_motion_and_update(mval);
1101 UNUSED_VARS(use_cycle);
1102 }
1103
1104 /* Cursors, for time being set always on edges,
1105 * otherwise the active region doesn't switch. */
1106 if (screen->active_region == nullptr) {
1107 screen_cursor_set(win, xy);
1108 }
1109 else {
1110 /* Notifier invokes freeing the buttons... causing a bit too much redraws. */
1111 region_cursor_set_ex(win, area, screen->active_region, region_prev != screen->active_region);
1112
1113 if (region_prev != screen->active_region) {
1114 /* This used to be a notifier, but needs to be done immediate
1115 * because it can undo setting the right button as active due
1116 * to delayed notifier handling. */
1117 if (C) {
1119 }
1120 }
1121 }
1122}
1123
1125{
1126 wmWindow *win = CTX_wm_window(C);
1127 bScreen *screen = CTX_wm_screen(C);
1128 ScrArea *area = CTX_wm_area(C);
1129
1130 if (win && screen && area) {
1131 AZone *az = ED_area_actionzone_find_xy(area, win->eventstate->xy);
1132
1133 if (az && az->type == AZONE_REGION) {
1134 return 1;
1135 }
1136
1137 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1138 if (region == screen->active_region) {
1139 return 1;
1140 }
1141 }
1142 }
1143 return 0;
1144}
1145
1151 const rcti *rect,
1152 eSpace_Type space_type)
1153{
1154 ScrVert *bottom_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin);
1155 ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax);
1156 ScrVert *top_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymax);
1157 ScrVert *bottom_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymin);
1158
1159 screen_geom_edge_add_ex(area_map, bottom_left, top_left);
1160 screen_geom_edge_add_ex(area_map, top_left, top_right);
1161 screen_geom_edge_add_ex(area_map, top_right, bottom_right);
1162 screen_geom_edge_add_ex(area_map, bottom_right, bottom_left);
1163
1164 return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, space_type);
1165}
1166
1167static void screen_area_set_geometry_rect(ScrArea *area, const rcti *rect)
1168{
1169 area->v1->vec.x = rect->xmin;
1170 area->v1->vec.y = rect->ymin;
1171 area->v2->vec.x = rect->xmin;
1172 area->v2->vec.y = rect->ymax;
1173 area->v3->vec.x = rect->xmax;
1174 area->v3->vec.y = rect->ymax;
1175 area->v4->vec.x = rect->xmax;
1176 area->v4->vec.y = rect->ymin;
1177}
1178
1180 bScreen *screen,
1181 const eSpace_Type space_type,
1182 GlobalAreaAlign align,
1183 const rcti *rect,
1184 const short height_cur,
1185 const short height_min,
1186 const short height_max)
1187{
1188 /* Full-screens shouldn't have global areas. Don't touch them. */
1189 if (screen->state == SCREENFULL) {
1190 return;
1191 }
1192
1193 ScrArea *area = nullptr;
1194 LISTBASE_FOREACH (ScrArea *, area_iter, &win->global_areas.areabase) {
1195 if (area_iter->spacetype == space_type) {
1196 area = area_iter;
1197 break;
1198 }
1199 }
1200
1201 if (area) {
1203 }
1204 else {
1205 area = screen_area_create_with_geometry(&win->global_areas, rect, space_type);
1207
1208 /* Data specific to global areas. */
1209 area->global = static_cast<ScrGlobalAreaData *>(MEM_callocN(sizeof(*area->global), __func__));
1210 area->global->size_max = height_max;
1211 area->global->size_min = height_min;
1212 area->global->align = align;
1213 }
1214
1215 if (area->global->cur_fixed_height != height_cur) {
1216 /* Refresh layout if size changes. */
1217 area->global->cur_fixed_height = height_cur;
1218 screen->do_refresh = true;
1219 }
1220}
1221
1223{
1225}
1226
1228{
1229 const blender::int2 win_size = WM_window_native_pixel_size(win);
1230 const short size = screen_global_header_size();
1231 rcti rect;
1232
1233 BLI_rcti_init(&rect, 0, win_size[0] - 1, 0, win_size[1] - 1);
1234 rect.ymin = rect.ymax - size;
1235
1237 win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size, size);
1238}
1239
1241{
1242 const blender::int2 win_size = WM_window_native_pixel_size(win);
1243 const short size_min = 1;
1244 const short size_max = 0.85f * screen_global_header_size();
1245 const short size = (screen->flag & SCREEN_COLLAPSE_STATUSBAR) ? size_min : size_max;
1246 rcti rect;
1247
1248 BLI_rcti_init(&rect, 0, win_size[0] - 1, 0, win_size[1] - 1);
1249 rect.ymax = rect.ymin + size_max;
1250
1252 win, screen, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size, size_min, size_max);
1253}
1254
1256{
1257 /* Update screen flags from height in window, this is weak and perhaps
1258 * global areas should just become part of the screen instead. */
1260
1262
1264 if (area->global->cur_fixed_height == area->global->size_min) {
1265 if (area->spacetype == SPACE_STATUSBAR) {
1267 }
1268 }
1269 }
1270}
1271
1273{
1274 /* Don't create global area for child and temporary windows. */
1276 if ((win->parent != nullptr) || screen->temp) {
1277 if (win->global_areas.areabase.first) {
1278 screen->do_refresh = true;
1280 }
1281 return;
1282 }
1283
1286}
1287
1288/* -------------------------------------------------------------------- */
1289/* Screen changing */
1290
1292 bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
1293{
1294 UNUSED_VARS_NDEBUG(bmain);
1295 BLI_assert(BLI_findindex(&bmain->screens, screen_new) != -1);
1296
1297 if (screen_old != screen_new) {
1298 wmTimer *wt = screen_old->animtimer;
1299
1300 /* remove handlers referencing areas in old screen */
1301 LISTBASE_FOREACH (ScrArea *, area, &screen_old->areabase) {
1303 }
1304
1305 /* we put timer to sleep, so screen_exit has to think there's no timer */
1306 screen_old->animtimer = nullptr;
1307 if (wt) {
1308 WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
1309 }
1310 ED_screen_exit(C, win, screen_old);
1311
1312 /* Same scene, "transfer" playback to new screen. */
1313 if (wt) {
1314 screen_new->animtimer = wt;
1315 }
1316 }
1317}
1318
1320{
1321 Scene *scene = WM_window_get_active_scene(win);
1323 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
1324
1325 CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
1326
1328
1329 BKE_screen_view3d_scene_sync(screen, scene); /* sync new screen with scene data */
1332
1333 /* Makes button highlights work. */
1335}
1336
1338{
1339 Main *bmain = CTX_data_main(C);
1340 wmWindow *win = CTX_wm_window(C);
1342 WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, screen);
1343 bScreen *screen_old = CTX_wm_screen(C);
1344
1345 /* Get the actual layout/screen to be activated (guaranteed to be unused, even if that means
1346 * having to duplicate an existing one). */
1348 bmain, workspace, layout, layout, win);
1349 bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
1350
1351 screen_change_prepare(screen_old, screen_new, bmain, C, win);
1352
1353 if (screen_old != screen_new) {
1354 WM_window_set_active_screen(win, workspace, screen_new);
1355 screen_change_update(C, win, screen_new);
1356
1357 return true;
1358 }
1359
1360 return false;
1361}
1362
1364 ViewLayer *view_layer,
1365 ScrArea *area,
1366 View3D *v3d)
1367{
1368 /* fix any cameras that are used in the 3d view but not in the scene */
1369 BKE_screen_view3d_sync(v3d, scene);
1370
1371 BKE_view_layer_synced_ensure(scene, view_layer);
1372 if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
1373 v3d->camera = BKE_view_layer_camera_find(scene, view_layer);
1374 // XXX if (screen == curscreen) handle_view3d_lock();
1375 if (!v3d->camera) {
1376 ListBase *regionbase;
1377
1378 /* regionbase is in different place depending if space is active */
1379 if (v3d == area->spacedata.first) {
1380 regionbase = &area->regionbase;
1381 }
1382 else {
1383 regionbase = &v3d->regionbase;
1384 }
1385
1386 LISTBASE_FOREACH (ARegion *, region, regionbase) {
1387 if (region->regiontype == RGN_TYPE_WINDOW) {
1388 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1389 if (rv3d->persp == RV3D_CAMOB) {
1390 rv3d->persp = RV3D_PERSP;
1391 }
1392 }
1393 }
1394 }
1395 }
1396}
1397
1399 wmWindow *win,
1400 Scene *scene,
1401 const bool refresh_toolsystem)
1402{
1403#if 0
1404 ViewLayer *view_layer_old = WM_window_get_active_view_layer(win);
1405#endif
1406
1407 /* Switch scene. */
1408 win->scene = scene;
1409 if (CTX_wm_window(C) == win) {
1410 CTX_data_scene_set(C, scene);
1411 }
1412
1413 /* Ensure the view layer name is updated. */
1415 ViewLayer *view_layer = WM_window_get_active_view_layer(win);
1416
1417#if 0
1418 /* Mode Syncing. */
1419 if (view_layer_old) {
1420 WorkSpace *workspace = CTX_wm_workspace(C);
1421 Object *obact_new = BKE_view_layer_active_object_get(view_layer);
1422 UNUSED_VARS(obact_new);
1423 eObjectMode object_mode_old = workspace->object_mode;
1424 Object *obact_old = BKE_view_layer_active_object_get(view_layer_old);
1425 UNUSED_VARS(obact_old, object_mode_old);
1426 }
1427#endif
1428
1429 /* Update 3D view cameras. */
1430 const bScreen *screen = WM_window_get_active_screen(win);
1431 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1432 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
1433 if (sl->spacetype == SPACE_VIEW3D) {
1434 View3D *v3d = (View3D *)sl;
1435 screen_set_3dview_camera(scene, view_layer, area, v3d);
1436 }
1437 }
1438 }
1439
1440 if (refresh_toolsystem) {
1442 }
1443}
1444
1446{
1447 bScreen *newscreen = nullptr;
1448 ScrArea *newsa = nullptr;
1449 SpaceLink *newsl;
1450
1451 if (!area || area->full == nullptr) {
1453 newsa = static_cast<ScrArea *>(newscreen->areabase.first);
1454 BLI_assert(newsa->spacetype == SPACE_EMPTY);
1455 }
1456
1457 if (!newsa) {
1458 newsa = area;
1459 }
1460
1461 BLI_assert(newsa);
1462 newsl = static_cast<SpaceLink *>(newsa->spacedata.first);
1463
1464 /* Tag the active space before changing, so we can identify it when user wants to go back. */
1465 if (newsl && (newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) {
1467 }
1468
1469 ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY));
1470
1471 if (newscreen) {
1472 ED_screen_change(C, newscreen);
1473 }
1474
1475 return newsa;
1476}
1477
1479{
1480 BLI_assert(area->full);
1481
1482 if (area->flag & AREA_FLAG_STACKED_FULLSCREEN) {
1483 /* Stacked full-screen -> only go back to previous area and don't toggle out of full-screen. */
1484 ED_area_prevspace(C, area);
1485 }
1486 else {
1488 }
1489}
1490
1492{
1493 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
1494
1495 /* In case nether functions below run. */
1496 ED_area_tag_redraw(area);
1497
1499 ED_area_prevspace(C, area);
1500 }
1501
1502 if (area->full) {
1504 }
1505}
1506
1508{
1509 wmWindow *win = CTX_wm_window(C);
1510 SpaceLink *sl = static_cast<SpaceLink *>(area->spacedata.first);
1511 bScreen *screen = CTX_wm_screen(C);
1512 short state = (screen ? screen->state : short(SCREENMAXIMIZED));
1513
1514 /* If full-screen area has a temporary space (such as a file browser or full-screen render
1515 * overlaid on top of an existing setup) then return to the previous space. */
1516
1517 if (sl->next) {
1520 }
1521 else {
1522 ED_screen_state_toggle(C, win, area, state);
1523 }
1524 /* WARNING: 'area' may be freed */
1525 }
1526 /* otherwise just tile the area again */
1527 else {
1528 ED_screen_state_toggle(C, win, area, state);
1529 }
1530}
1531
1542 wmWindow *win,
1543 ScrArea *toggle_area,
1544 int state)
1545{
1546 Main *bmain = CTX_data_main(C);
1547 WorkSpace *workspace = WM_window_get_active_workspace(win);
1548
1549 /* change from SCREENNORMAL to new state */
1550 WorkSpaceLayout *layout_new;
1551 ScrArea *newa;
1552 char newname[MAX_ID_NAME - 2];
1553
1555
1556 bScreen *oldscreen = WM_window_get_active_screen(win);
1557
1558 oldscreen->state = state;
1559 SNPRINTF(newname, "%s-%s", oldscreen->id.name + 2, "nonnormal");
1560
1561 layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
1562
1563 bScreen *screen = BKE_workspace_layout_screen_get(layout_new);
1564 screen->state = state;
1565 screen->redraws_flag = oldscreen->redraws_flag;
1566 screen->temp = oldscreen->temp;
1567 screen->flag = oldscreen->flag;
1568
1569 /* timer */
1570 screen->animtimer = oldscreen->animtimer;
1571 oldscreen->animtimer = nullptr;
1572
1573 newa = (ScrArea *)screen->areabase.first;
1574
1575 /* swap area */
1576 if (toggle_area) {
1577 ED_area_data_swap(newa, toggle_area);
1578 newa->flag = toggle_area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
1579 }
1580
1581 if (state == SCREENFULL) {
1582 /* temporarily hide global areas */
1583 LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
1584 glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
1585 }
1586 /* temporarily hide the side panels/header */
1587 LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) {
1588 region->flagfullscreen = region->flag;
1589
1590 if (ELEM(region->regiontype,
1600 {
1601 region->flag |= RGN_FLAG_HIDDEN;
1602 }
1603 }
1604 }
1605
1606 if (toggle_area) {
1607 toggle_area->full = oldscreen;
1608 }
1609 newa->full = oldscreen;
1610
1611 ED_area_tag_refresh(newa);
1612
1613 return screen;
1614}
1615
1620
1622{
1624 WorkSpace *workspace = WM_window_get_active_workspace(win);
1625
1626 if (area) {
1627 /* ensure we don't have a button active anymore, can crash when
1628 * switching screens with tooltip open because region and tooltip
1629 * are no longer in the same screen */
1630 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1631 UI_blocklist_free(C, region);
1632 if (region->regiontimer) {
1633 WM_event_timer_remove(wm, nullptr, region->regiontimer);
1634 region->regiontimer = nullptr;
1635 }
1636 }
1637
1638 /* prevent hanging status prints */
1639 ED_area_status_text(area, nullptr);
1640 ED_workspace_status_text(C, nullptr);
1641 }
1642 bScreen *screen;
1643 if (area && area->full) {
1645 /* restoring back to SCREENNORMAL */
1646 screen = area->full; /* the old screen to restore */
1647 bScreen *oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
1648
1649 BLI_assert(BKE_workspace_layout_screen_get(layout_old) != screen);
1651
1652 screen->state = SCREENNORMAL;
1653 screen->flag = oldscreen->flag;
1654
1655 /* Find old area we may have swapped dummy space data to. It's swapped back here. */
1656 ScrArea *fullsa = nullptr;
1657 LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) {
1658 /* area to restore from is always first */
1659 if (old->full && !fullsa) {
1660 fullsa = old;
1661 }
1662
1663 /* clear full screen state */
1664 old->full = nullptr;
1665 }
1666
1667 area->full = nullptr;
1668
1669 if (state == SCREENFULL) {
1670 /* unhide global areas */
1671 LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) {
1672 glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
1673 }
1674 /* restore the old side panels/header visibility */
1675 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1676 region->flag = region->flagfullscreen;
1677 }
1678 }
1679
1680 if (fullsa) {
1681 ED_area_data_swap(fullsa, area);
1682 ED_area_tag_refresh(fullsa);
1683 }
1684
1685 /* animtimer back */
1686 screen->animtimer = oldscreen->animtimer;
1687 oldscreen->animtimer = nullptr;
1688
1689 ED_screen_change(C, screen);
1690
1691 BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
1692
1693 /* After we've restored back to SCREENNORMAL, we have to wait with
1694 * screen handling as it uses the area coords which aren't updated yet.
1695 * Without doing so, the screen handling gets wrong area coords,
1696 * which in worst case can lead to crashes (see #43139) */
1697 screen->skip_handling = true;
1698 }
1699 else {
1700 ScrArea *toggle_area = area;
1701
1702 /* use random area when we have no active one, e.g. when the
1703 * mouse is outside of the window and we open a file browser */
1704 if (!toggle_area || toggle_area->global) {
1705 bScreen *oldscreen = WM_window_get_active_screen(win);
1706 toggle_area = static_cast<ScrArea *>(oldscreen->areabase.first);
1707 }
1708
1709 screen = screen_state_to_nonnormal(C, win, toggle_area, state);
1710
1711 ED_screen_change(C, screen);
1712 }
1713
1714 BLI_assert(CTX_wm_screen(C) == screen);
1715 BLI_assert(CTX_wm_area(C) == nullptr); /* May have been freed. */
1716
1717 /* Setting the area is only needed for Python scripts that call
1718 * operators in succession before returning to the main event loop.
1719 * Without this, scripts can't run any operators that require
1720 * an area after toggling full-screen for example (see: #89526).
1721 * NOTE: an old comment stated this was "bad code",
1722 * however it doesn't cause problems so leave as-is. */
1723 CTX_wm_area_set(C, static_cast<ScrArea *>(screen->areabase.first));
1724
1725 return static_cast<ScrArea *>(screen->areabase.first);
1726}
1727
1729 const char *title,
1730 const rcti *rect_unscaled,
1731 eSpace_Type space_type,
1732 int display_type,
1733 bool dialog)
1734{
1735 ScrArea *area = nullptr;
1736
1737 switch (display_type) {
1739 if (WM_window_open(C,
1740 title,
1741 rect_unscaled,
1742 int(space_type),
1743 false,
1744 dialog,
1745 true,
1747 nullptr,
1748 nullptr))
1749 {
1750 area = CTX_wm_area(C);
1751 }
1752 break;
1754 ScrArea *ctx_area = CTX_wm_area(C);
1755
1756 if (ctx_area != nullptr && ctx_area->full) {
1757 area = ctx_area;
1758 ED_area_newspace(C, ctx_area, space_type, true);
1760 ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
1761 }
1762 else {
1763 area = ED_screen_full_newspace(C, ctx_area, int(space_type));
1764 ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
1765 }
1766 break;
1767 }
1768 }
1769
1770 return area;
1771}
1772
1773void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
1774{
1775 bScreen *screen = CTX_wm_screen(C);
1777 wmWindow *win = CTX_wm_window(C);
1778 Scene *scene = CTX_data_scene(C);
1779 bScreen *stopscreen = ED_screen_animation_playing(wm);
1780
1781 if (stopscreen) {
1782 WM_event_timer_remove(wm, win, stopscreen->animtimer);
1783 stopscreen->animtimer = nullptr;
1784 }
1785
1786 if (enable) {
1787 ScreenAnimData *sad = static_cast<ScreenAnimData *>(
1788 MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData"));
1789
1790 screen->animtimer = WM_event_timer_add(wm, win, TIMER0, (1.0 / FPS));
1791
1792 sad->region = CTX_wm_region(C);
1793 /* If start-frame is larger than current frame, we put current-frame on start-frame.
1794 * NOTE(ton): first frame then is not drawn! */
1795 if (PRVRANGEON) {
1796 if (scene->r.psfra > scene->r.cfra) {
1797 sad->sfra = scene->r.cfra;
1798 scene->r.cfra = scene->r.psfra;
1799 }
1800 else {
1801 sad->sfra = scene->r.cfra;
1802 }
1803 }
1804 else {
1805 if (scene->r.sfra > scene->r.cfra) {
1806 sad->sfra = scene->r.cfra;
1807 scene->r.cfra = scene->r.sfra;
1808 }
1809 else {
1810 sad->sfra = scene->r.cfra;
1811 }
1812 }
1813 sad->redraws = redraws;
1814 sad->flag |= (enable < 0) ? ANIMPLAY_FLAG_REVERSE : 0;
1815 sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0;
1816
1817 ScrArea *area = CTX_wm_area(C);
1818
1819 char spacetype = -1;
1820
1821 if (area) {
1822 spacetype = area->spacetype;
1823 }
1824
1826
1827 screen->animtimer->customdata = sad;
1828
1829 /* Seek audio to ensure playback in preview range with AV sync. */
1831 }
1832
1833 /* Notifier caught by top header, for button. */
1835}
1836
1837/* helper for screen_animation_play() - only to be used for TimeLine */
1839{
1840 ARegion *region_top_left = nullptr;
1841 int min = 10000;
1842
1843 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1844 if (area->spacetype == SPACE_VIEW3D) {
1845 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1846 if (region->regiontype == RGN_TYPE_WINDOW) {
1847 if (region->winrct.xmin - region->winrct.ymin < min) {
1848 region_top_left = region;
1849 min = region->winrct.xmin - region->winrct.ymin;
1850 }
1851 }
1852 }
1853 }
1854 }
1855
1856 return region_top_left;
1857}
1858
1860{
1861 if (screen && screen->animtimer) {
1862 wmTimer *wt = screen->animtimer;
1863 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
1864
1865 sad->redraws = redraws;
1866 sad->region = nullptr;
1867 if (redraws & TIME_REGION) {
1868 sad->region = time_top_left_3dwindow(screen);
1869 }
1870 }
1871}
1872
1873void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
1874{
1876
1877 DEG_time_tag_update(bmain);
1878
1879#ifdef DURIAN_CAMERA_SWITCH
1880 void *camera = BKE_scene_camera_switch_find(scene);
1881 if (camera && scene->camera != camera) {
1882 scene->camera = static_cast<Object *>(camera);
1883 /* are there cameras in the views that are not in the scene? */
1884 LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) {
1885 BKE_screen_view3d_scene_sync(screen, scene);
1886 }
1888 }
1889#endif
1890
1891 ED_clip_update_frame(bmain, scene->r.cfra);
1892
1893 /* this function applies the changes too */
1895}
1896
1897bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
1898{
1899 const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
1900
1901 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1902 switch (area->spacetype) {
1903 case SPACE_VIEW3D: {
1904 View3D *v3d;
1905
1906 if (!is_multiview) {
1907 continue;
1908 }
1909
1910 v3d = static_cast<View3D *>(area->spacedata.first);
1911 if (v3d->camera && v3d->stereo3d_camera == STEREO_3D_ID) {
1912 LISTBASE_FOREACH (ARegion *, region, &area->regionbase) {
1913 if (region->regiondata && region->regiontype == RGN_TYPE_WINDOW) {
1914 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1915 if (rv3d->persp == RV3D_CAMOB) {
1916 return true;
1917 }
1918 }
1919 }
1920 }
1921 break;
1922 }
1923 case SPACE_IMAGE: {
1924 SpaceImage *sima;
1925
1926 /* images should always show in stereo, even if
1927 * the file doesn't have views enabled */
1928 sima = static_cast<SpaceImage *>(area->spacedata.first);
1929 if (sima->image && BKE_image_is_stereo(sima->image) &&
1930 (sima->iuser.flag & IMA_SHOW_STEREO))
1931 {
1932 return true;
1933 }
1934 break;
1935 }
1936 case SPACE_NODE: {
1937 SpaceNode *snode;
1938
1939 if (!is_multiview) {
1940 continue;
1941 }
1942
1943 snode = static_cast<SpaceNode *>(area->spacedata.first);
1944 if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
1945 return true;
1946 }
1947 break;
1948 }
1949 case SPACE_SEQ: {
1950 SpaceSeq *sseq;
1951
1952 if (!is_multiview) {
1953 continue;
1954 }
1955
1956 sseq = static_cast<SpaceSeq *>(area->spacedata.first);
1958 return true;
1959 }
1960
1961 if (sseq->draw_flag & SEQ_DRAW_BACKDROP) {
1962 return true;
1963 }
1964
1965 break;
1966 }
1967 }
1968 }
1969
1970 return false;
1971}
1972
1974 const wmWindowManager *wm,
1975 wmWindow **r_window)
1976{
1977 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1978 if (WM_window_get_active_screen(win) == screen) {
1979 if (r_window) {
1980 *r_window = win;
1981 }
1982 return WM_window_get_active_scene(win);
1983 }
1984 }
1985
1986 /* Can by nullptr when accessing a screen that isn't active. */
1987 return nullptr;
1988}
1989
1991 const SpaceLink *sl,
1992 const bool only_visible)
1993{
1994 if (only_visible) {
1995 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
1996 if (area->spacedata.first == sl) {
1997 return area;
1998 }
1999 }
2000 }
2001 else {
2002 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
2003 if (BLI_findindex(&area->spacedata, sl) != -1) {
2004 return area;
2005 }
2006 }
2007 }
2008 return nullptr;
2009}
2010
2012{
2013 return ED_screen_scene_find_with_window(screen, wm, nullptr);
2014}
2015
2017{
2018 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2019 if (WM_window_get_active_screen(win) == screen) {
2020 return win;
2021 }
2022 }
2023 return nullptr;
2024}
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_unreachable()
Definition BLI_assert.h:97
#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
#define AREAMAP_FROM_SCREEN(screen)
@ AREA_FLAG_STACKED_FULLSCREEN
@ RGN_FLAG_HIDDEN
@ RGN_FLAG_POLL_FAILED
@ 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
@ TIME_REGION
@ TIME_ALL_3D_WIN
@ TIME_ALL_ANIM_WIN
GlobalAreaAlign
@ GLOBAL_AREA_ALIGN_BOTTOM
@ GLOBAL_AREA_ALIGN_TOP
@ SCREENFULL
@ SCREENMAXIMIZED
@ SCREENNORMAL
@ SCREEN_COLLAPSE_STATUSBAR
@ 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
@ V2D_IS_INIT
@ 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:2596
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:2220
#define ED_screen_verts_iter(win, screen, vert_name)
Definition ED_screen.hh:288
void ED_area_and_region_types_init(ScrArea *area)
Definition area.cc:2036
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:285
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:3670
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:2258
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:2746
void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area)
Definition area.cc:2053
@ 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
static void split(const char *text, const char *seps, char ***str, int *count)
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:2285
void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src)
Definition area.cc:2318
#define U
BPy_StructRNA * depsgraph
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define printf
#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
uint top
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]
static int left
#define G(x, y, z)
VecBase< int32_t, 2 > int2
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
bool(* poll)(const RegionPollParams *params)
void(* exit)(wmWindowManager *wm, ARegion *region)
short event_cursor
struct wmTimer * regiontimer
char * headerstr
ListBase handlers
struct wmGizmoMap * gizmo_map
struct ARegionType * type
AZEdge edge
const char * name
Definition RNA_types.hh:510
int icon_id
Definition DNA_ID.h:436
char name[66]
Definition DNA_ID.h:425
void * first
ListBase screens
Definition BKE_main.hh:225
ListBase workspaces
Definition BKE_main.hh:246
struct RenderData r
struct Object * camera
ListBase areabase
ListBase handlers
ScrVert * v2
ScrVert * v3
ListBase spacedata
struct SpaceType * type
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
int(* space_icon_get)(const ScrArea *area)
void(* exit)(wmWindowManager *wm, ScrArea *area)
Definition BKE_screen.hh:89
blender::StringRefNull(* space_name_get)(const ScrArea *area)
struct Object * camera
char stereo3d_camera
ListBase regionbase
Wrapper for bScreen.
ListBase edgebase
void * context
short redraws_flag
ListBase regionbase
char skip_handling
ListBase vertbase
struct wmTimer * animtimer
ListBase areabase
struct ARegion * active_region
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)