diff options
Diffstat (limited to 'source/blender/editors/screen/screen_edit.c')
-rw-r--r-- | source/blender/editors/screen/screen_edit.c | 1117 |
1 files changed, 485 insertions, 632 deletions
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 82552c35786..53abe3ed4ea 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -33,7 +33,9 @@ #include "MEM_guardedalloc.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_workspace_types.h" #include "DNA_userdef_types.h" #include "BLI_math.h" @@ -41,18 +43,17 @@ #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_depsgraph.h" +#include "BKE_icons.h" #include "BKE_image.h" #include "BKE_global.h" +#include "BKE_layer.h" #include "BKE_library.h" #include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_screen.h" #include "BKE_scene.h" - -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "BKE_workspace.h" #include "WM_api.h" #include "WM_types.h" @@ -66,198 +67,43 @@ #include "UI_interface.h" -/* XXX actually should be not here... solve later */ -#include "wm_subwindow.h" +#include "WM_message.h" + +#include "DEG_depsgraph_query.h" #include "screen_intern.h" /* own module include */ /* ******************* screen vert, edge, area managing *********************** */ -static ScrVert *screen_addvert(bScreen *sc, short x, short y) +static ScrVert *screen_addvert_ex(ScrAreaMap *area_map, short x, short y) { ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert"); sv->vec.x = x; sv->vec.y = y; - BLI_addtail(&sc->vertbase, sv); + BLI_addtail(&area_map->vertbase, sv); return sv; } - -static void sortscrvert(ScrVert **v1, ScrVert **v2) +static ScrVert *screen_addvert(bScreen *sc, short x, short y) { - ScrVert *tmp; - - if (*v1 > *v2) { - tmp = *v1; - *v1 = *v2; - *v2 = tmp; - } + return screen_addvert_ex(AREAMAP_FROM_SCREEN(sc), x, y); } -static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2) +static ScrEdge *screen_addedge_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2) { ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge"); - sortscrvert(&v1, &v2); + BKE_screen_sort_scrvert(&v1, &v2); se->v1 = v1; se->v2 = v2; - BLI_addtail(&sc->edgebase, se); + BLI_addtail(&area_map->edgebase, se); return se; } - - -ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2) -{ - ScrEdge *se; - - sortscrvert(&v1, &v2); - for (se = sc->edgebase.first; se; se = se->next) - if (se->v1 == v1 && se->v2 == v2) - return se; - - return NULL; -} - -void removedouble_scrverts(bScreen *sc) -{ - ScrVert *v1, *verg; - ScrEdge *se; - ScrArea *sa; - - verg = sc->vertbase.first; - while (verg) { - if (verg->newv == NULL) { /* !!! */ - v1 = verg->next; - while (v1) { - if (v1->newv == NULL) { /* !?! */ - if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) { - /* printf("doublevert\n"); */ - v1->newv = verg; - } - } - v1 = v1->next; - } - } - verg = verg->next; - } - - /* replace pointers in edges and faces */ - se = sc->edgebase.first; - while (se) { - if (se->v1->newv) se->v1 = se->v1->newv; - if (se->v2->newv) se->v2 = se->v2->newv; - /* edges changed: so.... */ - sortscrvert(&(se->v1), &(se->v2)); - se = se->next; - } - sa = sc->areabase.first; - while (sa) { - if (sa->v1->newv) sa->v1 = sa->v1->newv; - if (sa->v2->newv) sa->v2 = sa->v2->newv; - if (sa->v3->newv) sa->v3 = sa->v3->newv; - if (sa->v4->newv) sa->v4 = sa->v4->newv; - sa = sa->next; - } - - /* remove */ - verg = sc->vertbase.first; - while (verg) { - v1 = verg->next; - if (verg->newv) { - BLI_remlink(&sc->vertbase, verg); - MEM_freeN(verg); - } - verg = v1; - } - -} - -void removenotused_scrverts(bScreen *sc) -{ - ScrVert *sv, *svn; - ScrEdge *se; - - /* we assume edges are ok */ - - se = sc->edgebase.first; - while (se) { - se->v1->flag = 1; - se->v2->flag = 1; - se = se->next; - } - - sv = sc->vertbase.first; - while (sv) { - svn = sv->next; - if (sv->flag == 0) { - BLI_remlink(&sc->vertbase, sv); - MEM_freeN(sv); - } - else { - sv->flag = 0; - } - sv = svn; - } -} - -void removedouble_scredges(bScreen *sc) -{ - ScrEdge *verg, *se, *sn; - - /* compare */ - verg = sc->edgebase.first; - while (verg) { - se = verg->next; - while (se) { - sn = se->next; - if (verg->v1 == se->v1 && verg->v2 == se->v2) { - BLI_remlink(&sc->edgebase, se); - MEM_freeN(se); - } - se = sn; - } - verg = verg->next; - } -} - -void removenotused_scredges(bScreen *sc) +static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2) { - ScrEdge *se, *sen; - ScrArea *sa; - int a = 0; - - /* sets flags when edge is used in area */ - sa = sc->areabase.first; - while (sa) { - se = screen_findedge(sc, sa->v1, sa->v2); - if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a); - else se->flag = 1; - se = screen_findedge(sc, sa->v2, sa->v3); - if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a); - else se->flag = 1; - se = screen_findedge(sc, sa->v3, sa->v4); - if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a); - else se->flag = 1; - se = screen_findedge(sc, sa->v4, sa->v1); - if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a); - else se->flag = 1; - sa = sa->next; - a++; - } - se = sc->edgebase.first; - while (se) { - sen = se->next; - if (se->flag == 0) { - BLI_remlink(&sc->edgebase, se); - MEM_freeN(se); - } - else { - se->flag = 0; - } - se = sen; - } + return screen_addedge_ex(AREAMAP_FROM_SCREEN(sc), v1, v2); } bool scredge_is_horizontal(ScrEdge *se) @@ -265,19 +111,21 @@ bool scredge_is_horizontal(ScrEdge *se) return (se->v1->vec.y == se->v2->vec.y); } -/* need win size to make sure not to include edges along screen edge */ -ScrEdge *screen_find_active_scredge(bScreen *sc, - const int winsize_x, const int winsize_y, - const int mx, const int my) +/** + * \param bounds_rect: Either window or screen bounds. Used to exclude edges along window/screen edges. + */ +ScrEdge *screen_area_map_find_active_scredge( + const ScrAreaMap *area_map, + const rcti *bounds_rect, + const int mx, const int my) { - ScrEdge *se; int safety = U.widget_unit / 10; - if (safety < 2) safety = 2; + CLAMP_MIN(safety, 2); - for (se = sc->edgebase.first; se; se = se->next) { + for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) { if (scredge_is_horizontal(se)) { - if (se->v1->vec.y > 0 && se->v1->vec.y < winsize_y - 1) { + if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) { short min, max; min = MIN2(se->v1->vec.x, se->v2->vec.x); max = MAX2(se->v1->vec.x, se->v2->vec.x); @@ -287,7 +135,7 @@ ScrEdge *screen_find_active_scredge(bScreen *sc, } } else { - if (se->v1->vec.x > 0 && se->v1->vec.x < winsize_x - 1) { + if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) { short min, max; min = MIN2(se->v1->vec.y, se->v2->vec.y); max = MAX2(se->v1->vec.y, se->v2->vec.y); @@ -301,23 +149,55 @@ ScrEdge *screen_find_active_scredge(bScreen *sc, return NULL; } +/* need win size to make sure not to include edges along screen edge */ +ScrEdge *screen_find_active_scredge( + const wmWindow *win, const bScreen *screen, + const int mx, const int my) +{ + /* Use layout size (screen excluding global areas) for screen-layout area edges */ + rcti screen_rect; + ScrEdge *se; + + WM_window_screen_rect_calc(win, &screen_rect); + se = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my); + + if (!se) { + /* Use entire window size (screen including global areas) for global area edges */ + rcti win_rect; + WM_window_rect_calc(win, &win_rect); + se = screen_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my); + } + return se; +} + /* adds no space data */ -static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype) +static ScrArea *screen_addarea_ex( + ScrAreaMap *area_map, + ScrVert *bottom_left, ScrVert *top_left, ScrVert *top_right, ScrVert *bottom_right, + short spacetype) { ScrArea *sa = MEM_callocN(sizeof(ScrArea), "addscrarea"); - sa->v1 = v1; - sa->v2 = v2; - sa->v3 = v3; - sa->v4 = v4; - sa->headertype = headertype; - sa->spacetype = sa->butspacetype = spacetype; - BLI_addtail(&sc->areabase, sa); + sa->v1 = bottom_left; + sa->v2 = top_left; + sa->v3 = top_right; + sa->v4 = bottom_right; + sa->spacetype = spacetype; + + BLI_addtail(&area_map->areabase, sa); return sa; } +static ScrArea *screen_addarea( + bScreen *sc, + ScrVert *left_bottom, ScrVert *left_top, ScrVert *right_top, ScrVert *right_bottom, + short spacetype) +{ + return screen_addarea_ex(AREAMAP_FROM_SCREEN(sc), left_bottom, left_top, right_top, right_bottom, + spacetype); +} static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa) { @@ -346,24 +226,24 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac) CLAMP(fac, 0.0f, 1.0f); if (dir == 'h') { - y = sa->v1->vec.y + fac * (sa->v2->vec.y - sa->v1->vec.y); + y = sa->v1->vec.y + + round_fl_to_short(fac * (float)(sa->v2->vec.y - sa->v1->vec.y)); if (y - sa->v1->vec.y < area_min_y) y = sa->v1->vec.y + area_min_y; else if (sa->v2->vec.y - y < area_min_y) y = sa->v2->vec.y - area_min_y; - else y -= (y % AREAGRID); return y; } else { - x = sa->v1->vec.x + fac * (sa->v4->vec.x - sa->v1->vec.x); + x = sa->v1->vec.x + + round_fl_to_short(fac * (float)(sa->v4->vec.x - sa->v1->vec.x)); if (x - sa->v1->vec.x < area_min_x) x = sa->v1->vec.x + area_min_x; else if (sa->v4->vec.x - x < area_min_x) x = sa->v4->vec.x - area_min_x; - else x -= (x % AREAGRID); return x; } @@ -398,7 +278,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) if (fac > 0.5f) { /* new areas: top */ - newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype); + newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->spacetype); /* area below */ sa->v2 = sv1; @@ -406,7 +286,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) } else { /* new areas: bottom */ - newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->headertype, sa->spacetype); + newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->spacetype); /* area above */ sa->v1 = sv1; @@ -430,7 +310,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) if (fac > 0.5f) { /* new areas: right */ - newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->headertype, sa->spacetype); + newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->spacetype); /* area left */ sa->v3 = sv2; @@ -438,7 +318,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) } else { /* new areas: left */ - newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype); + newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->spacetype); /* area right */ sa->v1 = sv1; @@ -450,33 +330,29 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) /* remove double vertices en edges */ if (merge) - removedouble_scrverts(sc); - removedouble_scredges(sc); - removenotused_scredges(sc); + BKE_screen_remove_double_scrverts(sc); + BKE_screen_remove_double_scredges(sc); + BKE_screen_remove_unused_scredges(sc); return newa; } -/* empty screen, with 1 dummy area without spacedata */ -/* uses window size */ -bScreen *ED_screen_add(Main *bmain, wmWindow *win, Scene *scene, const char *name) +/** + * Empty screen, with 1 dummy area without spacedata. Uses window size. + */ +bScreen *screen_add(Main *bmain, const char *name, const rcti *rect) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - bScreen *sc; ScrVert *sv1, *sv2, *sv3, *sv4; sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0); - sc->scene = scene; sc->do_refresh = true; sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN; - sc->winid = win->winid; - sv1 = screen_addvert(sc, 0, 0); - sv2 = screen_addvert(sc, 0, winsize_y - 1); - sv3 = screen_addvert(sc, winsize_x - 1, winsize_y - 1); - sv4 = screen_addvert(sc, winsize_x - 1, 0); + sv1 = screen_addvert(sc, rect->xmin, rect->ymin); + sv2 = screen_addvert(sc, rect->xmin, rect->ymax - 1); + sv3 = screen_addvert(sc, rect->xmax - 1, rect->ymax - 1); + sv4 = screen_addvert(sc, rect->xmax - 1, rect->ymin); screen_addedge(sc, sv1, sv2); screen_addedge(sc, sv2, sv3); @@ -484,12 +360,12 @@ bScreen *ED_screen_add(Main *bmain, wmWindow *win, Scene *scene, const char *nam screen_addedge(sc, sv4, sv1); /* dummy type, no spacedata */ - screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY); + screen_addarea(sc, sv1, sv2, sv3, sv4, SPACE_EMPTY); return sc; } -static void screen_copy(bScreen *to, bScreen *from) +void screen_data_copy(bScreen *to, bScreen *from) { ScrVert *s1, *s2; ScrEdge *se; @@ -511,7 +387,7 @@ static void screen_copy(bScreen *to, bScreen *from) for (se = to->edgebase.first; se; se = se->next) { se->v1 = se->v1->newv; se->v2 = se->v2->newv; - sortscrvert(&(se->v1), &(se->v2)); + BKE_screen_sort_scrvert(&(se->v1), &(se->v2)); } saf = from->areabase.first; @@ -532,7 +408,16 @@ static void screen_copy(bScreen *to, bScreen *from) /* put at zero (needed?) */ for (s1 = from->vertbase.first; s1; s1 = s1->next) s1->newv = NULL; +} +/** + * Prepare a newly created screen for initializing it as active screen. + */ +void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new) +{ + screen_new->winid = win->winid; + screen_new->do_refresh = true; + screen_new->do_draw = true; } @@ -611,15 +496,17 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) } screen_delarea(C, scr, sa2); - removedouble_scrverts(scr); + BKE_screen_remove_double_scrverts(scr); + /* Update preview thumbnail */ + BKE_icon_changed(scr->id.icon_id); return 1; } -void select_connected_scredge(bScreen *sc, ScrEdge *edge) +void select_connected_scredge(const wmWindow *win, ScrEdge *edge) { + bScreen *sc = WM_window_get_active_screen(win); ScrEdge *se; - ScrVert *sv; int oneselected; char dir; @@ -629,10 +516,8 @@ void select_connected_scredge(bScreen *sc, ScrEdge *edge) if (edge->v1->vec.x == edge->v2->vec.x) dir = 'v'; else dir = 'h'; - sv = sc->vertbase.first; - while (sv) { + ED_screen_verts_iter(win, sc, sv) { sv->flag = 0; - sv = sv->next; } edge->v1->flag = 1; @@ -662,18 +547,24 @@ void select_connected_scredge(bScreen *sc, ScrEdge *edge) } } -/* test if screen vertices should be scaled */ -static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) +/** + * Test if screen vertices should be scaled and do if needed. + */ +static void screen_vertices_scale( + const wmWindow *win, bScreen *sc, + const rcti *window_rect, const rcti *screen_rect) { /* clamp Y size of header sized areas when expanding windows * avoids annoying empty space around file menu */ #define USE_HEADER_SIZE_CLAMP const int headery_init = ED_area_headersize(); + const int screen_size_x = BLI_rcti_size_x(screen_rect); + const int screen_size_y = BLI_rcti_size_y(screen_rect); ScrVert *sv = NULL; ScrArea *sa; - int winsize_x_prev, winsize_y_prev; - float facx, facy, tempf, min[2], max[2]; + int screen_size_x_prev, screen_size_y_prev; + float min[2], max[2]; /* calculate size */ min[0] = min[1] = 20000.0f; @@ -684,14 +575,8 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) minmax_v2v2_v2(min, max, fv); } - /* always make 0.0 left under */ - for (sv = sc->vertbase.first; sv; sv = sv->next) { - sv->vec.x -= min[0]; - sv->vec.y -= min[1]; - } - - winsize_x_prev = (max[0] - min[0]) + 1; - winsize_y_prev = (max[1] - min[1]) + 1; + screen_size_x_prev = (max[0] - min[0]) + 1; + screen_size_y_prev = (max[1] - min[1]) + 1; #ifdef USE_HEADER_SIZE_CLAMP @@ -699,19 +584,19 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) #define TEMP_TOP 2 /* if the window's Y axis grows, clamp header sized areas */ - if (winsize_y_prev < winsize_y) { /* growing? */ + if (screen_size_y_prev < screen_size_y) { /* growing? */ const int headery_margin_max = headery_init + 4; for (sa = sc->areabase.first; sa; sa = sa->next) { ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); sa->temp = 0; if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) { - if (sa->v2->vec.y == winsize_y_prev - 1) { + if (sa->v2->vec.y == max[1]) { if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) { sa->temp = TEMP_TOP; } } - else if (sa->v1->vec.y == 0) { + else if (sa->v1->vec.y == min[1]) { if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) { sa->temp = TEMP_BOTTOM; } @@ -722,33 +607,23 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) #endif - if (winsize_x_prev != winsize_x || winsize_y_prev != winsize_y) { - facx = ((float)winsize_x - 1) / ((float)winsize_x_prev - 1); - facy = ((float)winsize_y - 1) / ((float)winsize_y_prev - 1); + if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) { + const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1); + const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1); /* make sure it fits! */ for (sv = sc->vertbase.first; sv; sv = sv->next) { - /* FIXME, this re-sizing logic is no good when re-sizing the window + redrawing [#24428] - * need some way to store these as floats internally and re-apply from there. */ - tempf = ((float)sv->vec.x) * facx; - sv->vec.x = (short)(tempf + 0.5f); - //sv->vec.x += AREAGRID - 1; - //sv->vec.x -= (sv->vec.x % AREAGRID); + sv->vec.x = screen_rect->xmin + round_fl_to_short((sv->vec.x - min[0]) * facx); + CLAMP(sv->vec.x, screen_rect->xmin, screen_rect->xmax - 1); - CLAMP(sv->vec.x, 0, winsize_x - 1); - - tempf = ((float)sv->vec.y) * facy; - sv->vec.y = (short)(tempf + 0.5f); - //sv->vec.y += AREAGRID - 1; - //sv->vec.y -= (sv->vec.y % AREAGRID); - - CLAMP(sv->vec.y, 0, winsize_y - 1); + sv->vec.y = screen_rect->ymin + round_fl_to_short((sv->vec.y - min[1]) * facy); + CLAMP(sv->vec.y, screen_rect->ymin, screen_rect->ymax - 1); } } #ifdef USE_HEADER_SIZE_CLAMP - if (winsize_y_prev < winsize_y) { /* growing? */ + if (screen_size_y_prev < screen_size_y) { /* growing? */ for (sa = sc->areabase.first; sa; sa = sa->next) { ScrEdge *se = NULL; @@ -762,9 +637,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) if (sa->temp == TEMP_TOP) { /* lower edge */ const int yval = sa->v2->vec.y - headery_init; - se = screen_findedge(sc, sa->v4, sa->v1); + se = BKE_screen_find_edge(sc, sa->v4, sa->v1); if (se != NULL) { - select_connected_scredge(sc, se); + select_connected_scredge(win, se); } for (sv = sc->vertbase.first; sv; sv = sv->next) { if (sv != sa->v2 && sv != sa->v3) { @@ -777,9 +652,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) else { /* upper edge */ const int yval = sa->v1->vec.y + headery_init; - se = screen_findedge(sc, sa->v2, sa->v3); + se = BKE_screen_find_edge(sc, sa->v2, sa->v3); if (se != NULL) { - select_connected_scredge(sc, se); + select_connected_scredge(win, se); } for (sv = sc->vertbase.first; sv; sv = sv->next) { if (sv != sa->v1 && sv != sa->v4) { @@ -806,21 +681,20 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) int headery = headery_init; /* adjust headery if verts are along the edge of window */ - if (sa->v1->vec.y > 0) + if (sa->v1->vec.y > window_rect->ymin) headery += U.pixelsize; - if (sa->v2->vec.y < winsize_y - 1) + if (sa->v2->vec.y < window_rect->ymax) headery += U.pixelsize; if (sa->v2->vec.y - sa->v1->vec.y + 1 < headery) { /* lower edge */ - ScrEdge *se = screen_findedge(sc, sa->v4, sa->v1); + ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1); if (se && sa->v1 != sa->v2) { - int yval; + const int yval = sa->v2->vec.y - headery + 1; - select_connected_scredge(sc, se); + select_connected_scredge(win, se); /* all selected vertices get the right offset */ - yval = sa->v2->vec.y - headery + 1; for (sv = sc->vertbase.first; sv; sv = sv->next) { /* if is a collapsed area */ if (sv != sa->v2 && sv != sa->v3) { @@ -833,31 +707,45 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) } } + /* Global areas have a fixed size that only changes with the DPI. Here we ensure that exactly this size is set. */ + for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) { + if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) { + continue; + } + /* width */ + area->v1->vec.x = area->v2->vec.x = window_rect->xmin; + area->v3->vec.x = area->v4->vec.x = window_rect->xmax - 1; + /* height */ + area->v1->vec.y = area->v4->vec.y = window_rect->ymin; + area->v2->vec.y = area->v3->vec.y = window_rect->ymax - 1; + switch (area->global->align) { + case GLOBAL_AREA_ALIGN_TOP: + area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - ED_area_global_size_y(area); + break; + case GLOBAL_AREA_ALIGN_BOTTOM: + area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + ED_area_global_size_y(area); + break; + } + } } + /* ****************** EXPORTED API TO OTHER MODULES *************************** */ -bScreen *ED_screen_duplicate(Main *bmain, wmWindow *win, bScreen *sc) +/* screen sets cursor based on active region */ +static void region_cursor_set(wmWindow *win, bool swin_changed) { - bScreen *newsc; - - if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */ + bScreen *screen = WM_window_get_active_screen(win); - /* make new empty screen: */ - newsc = ED_screen_add(bmain, win, sc->scene, sc->id.name + 2); - /* copy all data */ - screen_copy(newsc, sc); - - return newsc; -} - -/* screen sets cursor based on swinid */ -static void region_cursor_set(wmWindow *win, int swinid, int swin_changed) -{ - for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) { + ED_screen_areas_iter(win, screen, sa) { for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->swinid == swinid) { + if (ar == screen->active_region) { if (swin_changed || (ar->type && ar->type->event_cursor)) { + if (ar->manipulator_map != NULL) { + if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) { + return; + } + } ED_region_cursor_set(win, sa, ar); } return; @@ -869,23 +757,24 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed) void ED_screen_do_listen(bContext *C, wmNotifier *note) { wmWindow *win = CTX_wm_window(C); + bScreen *screen = CTX_wm_screen(C); /* generic notes */ switch (note->category) { case NC_WM: if (note->data == ND_FILEREAD) - win->screen->do_draw = true; + screen->do_draw = true; break; case NC_WINDOW: - win->screen->do_draw = true; + screen->do_draw = true; break; case NC_SCREEN: if (note->action == NA_EDITED) - win->screen->do_draw = win->screen->do_refresh = true; + screen->do_draw = screen->do_refresh = true; break; case NC_SCENE: if (note->data == ND_MODE) - region_cursor_set(win, note->swinid, true); + region_cursor_set(win, true); break; } } @@ -906,48 +795,40 @@ static void screen_refresh_headersizes(void) /* for file read and first use, for scaling window, area moves */ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) { + bScreen *screen = WM_window_get_active_screen(win); + /* exception for bg mode, we only need the screen context */ if (!G.background) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - ScrArea *sa; - rcti winrct; - - winrct.xmin = 0; - winrct.xmax = winsize_x - 1; - winrct.ymin = 0; - winrct.ymax = winsize_y - 1; + rcti window_rect, screen_rect; /* header size depends on DPI, let's verify */ WM_window_set_dpi(win); screen_refresh_headersizes(); - screen_test_scale(win->screen, winsize_x, winsize_y); + WM_window_rect_calc(win, &window_rect); + WM_window_screen_rect_calc(win, &screen_rect); /* Get screen bounds __after__ updating window DPI! */ - if (win->screen->mainwin == 0) { - win->screen->mainwin = wm_subwindow_open(win, &winrct, false); - } - else { - wm_subwindow_position(win, win->screen->mainwin, &winrct, false); - } + screen_vertices_scale(win, screen, &window_rect, &screen_rect); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { + ED_screen_areas_iter(win, screen, area) { /* set spacetype and region callbacks, calls init() */ /* sets subwindows for regions, adds handlers */ - ED_area_initialize(wm, win, sa); + ED_area_initialize(wm, win, area); } /* wake up animtimer */ - if (win->screen->animtimer) - WM_event_timer_sleep(wm, win, win->screen->animtimer, false); + if (screen->animtimer) + WM_event_timer_sleep(wm, win, screen->animtimer, false); } if (G.debug & G_DEBUG_EVENTS) { printf("%s: set screen\n", __func__); } - win->screen->do_refresh = false; + screen->do_refresh = false; + /* prevent multiwin errors */ + screen->winid = win->winid; - win->screen->context = ed_screen_context; + screen->context = ed_screen_context; } /* file read, set all screens, ... */ @@ -956,10 +837,23 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm) wmWindow *win; for (win = wm->windows.first; win; win = win->next) { + if (WM_window_get_active_workspace(win) == NULL) { + WM_window_set_active_workspace(win, bmain->workspaces.first); + } - if (win->screen == NULL) - win->screen = bmain->screen.first; + if (BLI_listbase_is_empty(&win->global_areas.areabase)) { + ED_screen_global_areas_create(win); + } + ED_screen_refresh(wm, win); + if (win->eventstate) { + ED_screen_set_active_region(NULL, win, &win->eventstate->x); + } + } +} +void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *screen) +{ + if (screen->do_refresh) { ED_screen_refresh(wm, win); } } @@ -970,17 +864,17 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm) void ED_region_exit(bContext *C, ARegion *ar) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); ARegion *prevar = CTX_wm_region(C); if (ar->type && ar->type->exit) ar->type->exit(wm, ar); CTX_wm_region_set(C, ar); + WM_event_remove_handlers(C, &ar->handlers); - if (ar->swinid) { - wm_subwindow_close(CTX_wm_window(C), ar->swinid); - ar->swinid = 0; - } + WM_event_modal_handler_region_replace(win, ar, NULL); + WM_draw_region_free(ar); if (ar->headerstr) { MEM_freeN(ar->headerstr); @@ -988,16 +882,19 @@ void ED_region_exit(bContext *C, ARegion *ar) } if (ar->regiontimer) { - WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer); + WM_event_remove_timer(wm, win, ar->regiontimer); ar->regiontimer = NULL; } + WM_msgbus_clear_by_owner(wm->message_bus, ar); + CTX_wm_region_set(C, prevar); } void ED_area_exit(bContext *C, ScrArea *sa) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *ar; @@ -1005,10 +902,13 @@ void ED_area_exit(bContext *C, ScrArea *sa) sa->type->exit(wm, sa); CTX_wm_area_set(C, sa); + for (ar = sa->regionbase.first; ar; ar = ar->next) ED_region_exit(C, ar); WM_event_remove_handlers(C, &sa->handlers); + WM_event_modal_handler_area_replace(win, sa, NULL); + CTX_wm_area_set(C, prevsa); } @@ -1016,8 +916,6 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *prevwin = CTX_wm_window(C); - ScrArea *sa; - ARegion *ar; CTX_wm_window_set(C, window); @@ -1026,21 +924,23 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen) screen->animtimer = NULL; screen->scrubbing = false; - if (screen->mainwin) - wm_subwindow_close(window, screen->mainwin); - screen->mainwin = 0; - screen->subwinactive = 0; + screen->active_region = NULL; - for (ar = screen->regionbase.first; ar; ar = ar->next) + for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) { ED_region_exit(C, ar); - - for (sa = screen->areabase.first; sa; sa = sa->next) + } + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { ED_area_exit(C, sa); + } + /* Don't use ED_screen_areas_iter here, it skips hidden areas. */ + for (ScrArea *sa = window->global_areas.areabase.first; sa; sa = sa->next) { + ED_area_exit(C, sa); + } /* mark it available for use for other windows */ screen->winid = 0; - if (prevwin->screen->temp == 0) { + if (!WM_window_is_temp_screen(prevwin)) { /* use previous window if possible */ CTX_wm_window_set(C, prevwin); } @@ -1054,16 +954,14 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen) /* *********************************** */ /* case when on area-edge or in azones, or outside window */ -static void screen_cursor_set(wmWindow *win, const wmEvent *event) +static void screen_cursor_set(wmWindow *win, const int xy[2]) { - const int winsize_x = WM_window_pixels_x(win); - const int winsize_y = WM_window_pixels_y(win); - + const bScreen *screen = WM_window_get_active_screen(win); AZone *az = NULL; ScrArea *sa; - for (sa = win->screen->areabase.first; sa; sa = sa->next) - if ((az = ED_area_actionzone_find_xy(sa, &event->x))) + for (sa = screen->areabase.first; sa; sa = sa->next) + if ((az = ED_area_actionzone_find_xy(sa, xy))) break; if (sa) { @@ -1077,7 +975,7 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event) } } else { - ScrEdge *actedge = screen_find_active_scredge(win->screen, winsize_x, winsize_y, event->x, event->y); + ScrEdge *actedge = screen_find_active_scredge(win, screen, xy[0], xy[1]); if (actedge) { if (scredge_is_horizontal(actedge)) @@ -1093,20 +991,20 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event) /* called in wm_event_system.c. sets state vars in screen, cursors */ /* event type is mouse move */ -void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) +void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2]) { - wmWindow *win = CTX_wm_window(C); + bScreen *scr = WM_window_get_active_screen(win); - if (win->screen) { - bScreen *scr = win->screen; - ScrArea *sa; + if (scr) { + ScrArea *sa = NULL; ARegion *ar; - int oldswin = scr->subwinactive; + ARegion *old_ar = scr->active_region; - for (sa = scr->areabase.first; sa; sa = sa->next) { - if (event->x > sa->totrct.xmin && event->x < sa->totrct.xmax) { - if (event->y > sa->totrct.ymin && event->y < sa->totrct.ymax) { - if (NULL == ED_area_actionzone_refresh_xy(sa, &event->x)) { + ED_screen_areas_iter(win, scr, area_iter) { + if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) { + if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) { + if (ED_area_actionzone_refresh_xy(area_iter, xy) == NULL) { + sa = area_iter; break; } } @@ -1115,49 +1013,55 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) if (sa) { /* make overlap active when mouse over */ for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) { - scr->subwinactive = ar->swinid; + if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) { + scr->active_region = ar; break; } } } else - scr->subwinactive = scr->mainwin; + scr->active_region = NULL; /* check for redraw headers */ - if (oldswin != scr->subwinactive) { + if (old_ar != scr->active_region) { - for (sa = scr->areabase.first; sa; sa = sa->next) { + ED_screen_areas_iter(win, scr, area_iter) { bool do_draw = false; - for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar->swinid == oldswin || ar->swinid == scr->subwinactive) + for (ar = area_iter->regionbase.first; ar; ar = ar->next) { + if (ar == old_ar || ar == scr->active_region) { do_draw = true; + } + } if (do_draw) { - for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar->regiontype == RGN_TYPE_HEADER) - ED_region_tag_redraw(ar); + for (ar = area_iter->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_HEADER) { + ED_region_tag_redraw_no_rebuild(ar); + } + } } } } /* cursors, for time being set always on edges, otherwise aregion doesnt switch */ - if (scr->subwinactive == scr->mainwin) { - screen_cursor_set(win, event); + if (scr->active_region == NULL) { + screen_cursor_set(win, xy); } else { /* notifier invokes freeing the buttons... causing a bit too much redraws */ - if (oldswin != scr->subwinactive) { - region_cursor_set(win, scr->subwinactive, true); + if (old_ar != scr->active_region) { + region_cursor_set(win, true); /* this used to be a notifier, but needs to be done immediate * because it can undo setting the right button as active due * to delayed notifier handling */ - UI_screen_free_active_but(C, win->screen); + if (C) { + UI_screen_free_active_but(C, scr); + } } else - region_cursor_set(win, scr->subwinactive, false); + region_cursor_set(win, false); } } } @@ -1176,183 +1080,199 @@ int ED_screen_area_active(const bContext *C) return 1; for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar->swinid == sc->subwinactive) + if (ar == sc->active_region) return 1; } return 0; } /** - * operator call, WM + Window + screen already existed before - * - * \warning Do NOT call in area/region queues! - * \returns success. + * Add an area and geometry (screen-edges and -vertices) for it to \a area_map, + * with coordinates/dimensions matching \a rect. */ -bool ED_screen_set(bContext *C, bScreen *sc) +static ScrArea *screen_area_create_with_geometry( + ScrAreaMap *area_map, const rcti *rect, + short spacetype) { - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - bScreen *oldscreen = CTX_wm_screen(C); + ScrVert *bottom_left = screen_addvert_ex(area_map, rect->xmin, rect->ymin); + ScrVert *top_left = screen_addvert_ex(area_map, rect->xmin, rect->ymax); + ScrVert *top_right = screen_addvert_ex(area_map, rect->xmax, rect->ymax); + ScrVert *bottom_right = screen_addvert_ex(area_map, rect->xmax, rect->ymin); - /* validate screen, it's called with notifier reference */ - if (BLI_findindex(&bmain->screen, sc) == -1) { - return true; + screen_addedge_ex(area_map, bottom_left, top_left); + screen_addedge_ex(area_map, top_left, top_right); + screen_addedge_ex(area_map, top_right, bottom_right); + screen_addedge_ex(area_map, bottom_right, bottom_left); + + return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype); +} + +static void screen_global_area_create( + wmWindow *win, eSpace_Type space_type, GlobalAreaAlign align, const rcti *rect, + const short height_cur, const short height_min, const short height_max) +{ + ScrArea *area = screen_area_create_with_geometry(&win->global_areas, rect, space_type); + SpaceType *stype = BKE_spacetype_from_id(space_type); + SpaceLink *slink = stype->new(area, WM_window_get_active_scene(win)); + + area->regionbase = slink->regionbase; + + /* Data specific to global areas. */ + area->global = MEM_callocN(sizeof(*area->global), __func__); + area->global->cur_fixed_height = height_cur; + area->global->size_max = height_max; + area->global->size_min = height_min; + area->global->align = align; + + BLI_addhead(&area->spacedata, slink); + BLI_listbase_clear(&slink->regionbase); +} + +static void screen_global_topbar_area_create(wmWindow *win) +{ + const short size_y = 2.25 * HEADERY; + rcti rect; + + BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1); + rect.ymin = rect.ymax - size_y; + + screen_global_area_create(win, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size_y, HEADERY, size_y); +} + +static void screen_global_statusbar_area_create(wmWindow *win) +{ + const short size_y = HEADERY; + rcti rect; + + BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1); + rect.ymax = rect.ymin + size_y; + + screen_global_area_create(win, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size_y, size_y, size_y); +} + +void ED_screen_global_areas_create(wmWindow *win) +{ + bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + if (screen->temp == 0) { + screen_global_topbar_area_create(win); + screen_global_statusbar_area_create(win); } +} - if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) { - /* find associated full */ - bScreen *sc1; - for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) { - ScrArea *sa = sc1->areabase.first; - if (sa->full == sc) { - sc = sc1; - break; - } + +/* -------------------------------------------------------------------- */ +/* Screen changing */ + +static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmain, bScreen *screen) +{ + for (bScreen *screen_iter = bmain->screen.first; screen_iter; screen_iter = screen_iter->id.next) { + ScrArea *sa = screen_iter->areabase.first; + if (sa && sa->full == screen) { + return screen_iter; } } + return screen; +} + +/** + * \return the screen to activate. + * \warning The returned screen may not always equal \a screen_new! + */ +bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win) +{ + /* validate screen, it's called with notifier reference */ + if (BLI_findindex(&bmain->screen, screen_new) == -1) { + return NULL; + } + + if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) { + screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new); + } + /* check for valid winid */ - if (sc->winid != 0 && sc->winid != win->winid) { - return false; + if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) { + return NULL; } - if (oldscreen != sc) { - wmTimer *wt = oldscreen->animtimer; - ScrArea *sa; - Scene *oldscene = oldscreen->scene; + if (screen_old != screen_new) { + wmTimer *wt = screen_old->animtimer; /* remove handlers referencing areas in old screen */ - for (sa = oldscreen->areabase.first; sa; sa = sa->next) { + for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) { WM_event_remove_area_handler(&win->modalhandlers, sa); } /* we put timer to sleep, so screen_exit has to think there's no timer */ - oldscreen->animtimer = NULL; + screen_old->animtimer = NULL; if (wt) { - WM_event_timer_sleep(wm, win, wt, true); + WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true); } - - ED_screen_exit(C, win, oldscreen); + ED_screen_exit(C, win, screen_old); /* Same scene, "transfer" playback to new screen. */ if (wt) { - if (oldscene == sc->scene) { - sc->animtimer = wt; - } - /* Else, stop playback. */ - else { - oldscreen->animtimer = wt; - ED_screen_animation_play(C, 0, 0); - } + screen_new->animtimer = wt; } - win->screen = sc; - CTX_wm_window_set(C, win); // stores C->wm.screen... hrmf - - /* prevent multiwin errors */ - sc->winid = win->winid; - - ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C)); - WM_event_add_notifier(C, NC_WINDOW, NULL); - WM_event_add_notifier(C, NC_SCREEN | ND_SCREENSET, sc); - - /* makes button hilites work */ - WM_event_add_mousemove(C); - - /* Needed to make sure all the derivedMeshes are - * up-to-date before viewport starts acquiring this. - * - * This is needed in cases when, for example, boolean - * modifier uses operant from invisible layer. - * Without this trick boolean wouldn't apply correct. - * - * Quite the same happens when setting screen's scene, - * so perhaps this is in fact correct thing to do. - */ - if (oldscene != sc->scene) { - BKE_scene_set_background(bmain, sc->scene); - } - - /* Always do visible update since it's possible new screen will - * have different layers visible in 3D view-ports. - * This is possible because of view3d.lock_camera_and_layers option. - */ - DAG_on_visible_update(bmain, false); + return screen_new; } - return true; + return NULL; } -static bool ed_screen_used(wmWindowManager *wm, bScreen *sc) +void screen_change_update(bContext *C, wmWindow *win, bScreen *sc) { - wmWindow *win; + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc); - for (win = wm->windows.first; win; win = win->next) { - if (win->screen == sc) { - return true; - } + CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */ - if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) { - ScrArea *sa = win->screen->areabase.first; - if (sa->full == sc) { - return true; - } - } - } + ED_screen_refresh(CTX_wm_manager(C), win); - return false; + BKE_screen_view3d_scene_sync(sc, scene); /* sync new screen with scene data */ + WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout); + + /* makes button hilites work */ + WM_event_add_mousemove(C); } -/* only call outside of area/region loops */ -bool ED_screen_delete(bContext *C, bScreen *sc) + +/** + * \brief Change the active screen. + * + * Operator call, WM + Window + screen already existed before + * + * \warning Do NOT call in area/region queues! + * \returns if screen changing was successful. + */ +bool ED_screen_change(bContext *C, bScreen *sc) { Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); - bScreen *newsc; + bScreen *screen_old = CTX_wm_screen(C); + bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win); - /* don't allow deleting temp fullscreens for now */ - if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) { - return false; - } - - /* screen can only be in use by one window at a time, so as - * long as we are able to find a screen that is unused, we - * can safely assume ours is not in use anywhere an delete it */ - - for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev) - if (!ed_screen_used(wm, newsc) && !newsc->temp) - break; - - if (!newsc) { - for (newsc = sc->id.next; newsc; newsc = newsc->id.next) - if (!ed_screen_used(wm, newsc) && !newsc->temp) - break; - } - - if (!newsc) { - return false; - } + if (screen_new) { + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + WM_window_set_active_screen(win, workspace, sc); + screen_change_update(C, win, screen_new); - ED_screen_set(C, newsc); - - if (win->screen != sc) { - BKE_libblock_free(bmain, sc); return true; } - else { - return false; - } + + return false; } -static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, View3D *v3d) +static void screen_set_3dview_camera(Scene *scene, ViewLayer *view_layer, ScrArea *sa, View3D *v3d) { /* fix any cameras that are used in the 3d view but not in the scene */ BKE_screen_view3d_sync(v3d, scene); - if (!v3d->camera || !BKE_scene_base_find(scene, v3d->camera)) { - v3d->camera = BKE_scene_camera_find(sc->scene); + if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) { + v3d->camera = BKE_view_layer_camera_find(view_layer); // XXX if (sc == curscreen) handle_view3d_lock(); if (!v3d->camera) { ARegion *ar; @@ -1376,100 +1296,21 @@ static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, } } -/* only call outside of area/region loops */ -void ED_screen_set_scene(bContext *C, bScreen *screen, Scene *scene) +void ED_screen_update_after_scene_change(const bScreen *screen, Scene *scene_new, ViewLayer *view_layer) { - Main *bmain = CTX_data_main(C); - bScreen *sc; - - if (screen == NULL) - return; - - if (ed_screen_used(CTX_wm_manager(C), screen)) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - for (sc = bmain->screen.first; sc; sc = sc->id.next) { - if ((U.flag & USER_SCENEGLOBAL) || sc == screen) { - - if (scene != sc->scene) { - /* all areas endlocalview */ - // XXX ScrArea *sa = sc->areabase.first; - // while (sa) { - // endlocalview(sa); - // sa = sa->next; - // } - sc->scene = scene; + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; + screen_set_3dview_camera(scene_new, view_layer, sa, v3d); } - } } - - // copy_view3d_lock(0); /* space.c */ - - /* are there cameras in the views that are not in the scene? */ - for (sc = bmain->screen.first; sc; sc = sc->id.next) { - if ((U.flag & USER_SCENEGLOBAL) || sc == screen) { - ScrArea *sa = sc->areabase.first; - while (sa) { - SpaceLink *sl = sa->spacedata.first; - while (sl) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - ed_screen_set_3dview_camera(scene, sc, sa, v3d); - - } - sl = sl->next; - } - sa = sa->next; - } - } - } - - CTX_data_scene_set(C, scene); - BKE_scene_set_background(bmain, scene); - DAG_on_visible_update(bmain, false); - - ED_render_engine_changed(bmain); - ED_update_for_newframe(bmain, scene, 1); - - /* complete redraw */ - WM_event_add_notifier(C, NC_WINDOW, NULL); - -} - -/** - * \note Only call outside of area/region loops - * \return true if successful - */ -bool ED_screen_delete_scene(bContext *C, Scene *scene) -{ - Main *bmain = CTX_data_main(C); - Scene *newscene; - - if (scene->id.prev) - newscene = scene->id.prev; - else if (scene->id.next) - newscene = scene->id.next; - else - return false; - - ED_screen_set_scene(C, CTX_wm_screen(C), newscene); - - BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); - - id_us_clear_real(&scene->id); - if (scene->id.us == 0) { - BKE_libblock_free(bmain, scene); - } - - return true; } ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) { wmWindow *win = CTX_wm_window(C); - bScreen *screen = CTX_wm_screen(C); ScrArea *newsa = NULL; if (!sa || sa->full == NULL) { @@ -1477,18 +1318,7 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) } if (!newsa) { - if (sa->full && (screen->state == SCREENMAXIMIZED)) { - /* if this has been called from the temporary info header generated in - * temp fullscreen layouts, find the correct fullscreen area to change - * to create a new space inside */ - for (newsa = screen->areabase.first; newsa; newsa = newsa->next) { - if (!(sa->flag & AREA_TEMP_INFO)) - break; - } - } - else { - newsa = sa; - } + newsa = sa; } BLI_assert(newsa); @@ -1571,6 +1401,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s { Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); bScreen *sc, *oldscreen; ARegion *ar; @@ -1592,9 +1423,10 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s } if (sa && sa->full) { + WorkSpaceLayout *layout_old = WM_window_get_active_layout(win); /* restoring back to SCREENNORMAL */ sc = sa->full; /* the old screen to restore */ - oldscreen = win->screen; /* the one disappearing */ + oldscreen = WM_window_get_active_screen(win); /* the one disappearing */ sc->state = SCREENNORMAL; @@ -1608,10 +1440,8 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s /* clear full screen state */ old->full = NULL; - old->flag &= ~AREA_TEMP_INFO; } - sa->flag &= ~AREA_TEMP_INFO; sa->full = NULL; if (fullsa == NULL) { @@ -1621,6 +1451,10 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s } if (state == SCREENFULL) { + /* unhide global areas */ + for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area; glob_area = glob_area->next) { + glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN; + } /* restore the old side panels/header visibility */ for (ar = sa->regionbase.first; ar; ar = ar->next) { ar->flag = ar->flagfullscreen; @@ -1633,9 +1467,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s sc->animtimer = oldscreen->animtimer; oldscreen->animtimer = NULL; - ED_screen_set(C, sc); + ED_screen_change(C, sc); - BKE_libblock_free(CTX_data_main(C), oldscreen); + BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old); /* After we've restored back to SCREENNORMAL, we have to wait with * screen handling as it uses the area coords which aren't updated yet. @@ -1645,14 +1479,20 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s } else { /* change from SCREENNORMAL to new state */ + WorkSpaceLayout *layout_new; ScrArea *newa; char newname[MAX_ID_NAME - 2]; - oldscreen = win->screen; + BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); + + oldscreen = WM_window_get_active_screen(win); oldscreen->state = state; BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); - sc = ED_screen_add(bmain, win, oldscreen->scene, newname); + + layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); + + sc = BKE_workspace_layout_screen_get(layout_new); sc->state = state; sc->redraws_flag = oldscreen->redraws_flag; sc->temp = oldscreen->temp; @@ -1663,51 +1503,35 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s /* use random area when we have no active one, e.g. when the * mouse is outside of the window and we open a file browser */ - if (!sa) + if (!sa || sa->global) { sa = oldscreen->areabase.first; - - if (state == SCREENMAXIMIZED) { - /* returns the top small area */ - newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1); - ED_area_newspace(C, newa, SPACE_INFO, false); - - /* copy area */ - newa = newa->prev; - ED_area_data_swap(newa, sa); - sa->flag |= AREA_TEMP_INFO; - - sa->full = oldscreen; - newa->full = oldscreen; - newa->next->full = oldscreen; // XXX } - else if (state == SCREENFULL) { - newa = (ScrArea *)sc->areabase.first; - /* copy area */ - ED_area_data_swap(newa, sa); - newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ + newa = (ScrArea *)sc->areabase.first; + /* copy area */ + ED_area_data_swap(newa, sa); + newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ + + if (state == SCREENFULL) { + /* temporarily hide global areas */ + for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area; glob_area = glob_area->next) { + glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; + } /* temporarily hide the side panels/header */ for (ar = newa->regionbase.first; ar; ar = ar->next) { ar->flagfullscreen = ar->flag; - if (ELEM(ar->regiontype, - RGN_TYPE_UI, - RGN_TYPE_HEADER, - RGN_TYPE_TOOLS)) - { + if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_HEADER, RGN_TYPE_TOOLS)) { ar->flag |= RGN_FLAG_HIDDEN; } } - - sa->full = oldscreen; - newa->full = oldscreen; - } - else { - BLI_assert(false); } - ED_screen_set(C, sc); + sa->full = oldscreen; + newa->full = oldscreen; + + ED_screen_change(C, sc); } /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */ @@ -1794,7 +1618,7 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync, if (sa) spacetype = sa->spacetype; - sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME)); + sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA)); screen->animtimer->customdata = sad; @@ -1842,13 +1666,10 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh) } } -/* results in fully updated anim system - * screen can be NULL */ -void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute)) +/* results in fully updated anim system */ +void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph) { - wmWindowManager *wm = bmain->wm.first; - wmWindow *window; - int layers = 0; + Scene *scene = DEG_get_input_scene(depsgraph); #ifdef DURIAN_CAMERA_SWITCH void *camera = BKE_scene_camera_switch_find(scene); @@ -1857,19 +1678,15 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute)) scene->camera = camera; /* are there cameras in the views that are not in the scene? */ for (sc = bmain->screen.first; sc; sc = sc->id.next) { - BKE_screen_view3d_scene_sync(sc); + BKE_screen_view3d_scene_sync(sc, scene); } } #endif ED_clip_update_frame(bmain, scene->r.cfra); - /* get layers from all windows */ - for (window = wm->windows.first; window; window = window->next) - layers |= BKE_screen_visible_layers(window->screen, scene); - /* this function applies the changes too */ - BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, layers); + BKE_scene_graph_update_for_newframe(depsgraph, bmain); /* composite */ if (scene->use_nodes && scene->nodetree) @@ -1890,11 +1707,10 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute)) /* * return true if any active area requires to see in 3D */ -bool ED_screen_stereo3d_required(bScreen *screen) +bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene) { ScrArea *sa; - Scene *sce = screen->scene; - const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0; + const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; for (sa = screen->areabase.first; sa; sa = sa->next) { switch (sa->spacetype) { @@ -1969,3 +1785,40 @@ bool ED_screen_stereo3d_required(bScreen *screen) return false; } + +/** + * Find the scene displayed in \a screen. + * \note Assumes \a screen to be visible/active! + */ + +Scene *ED_screen_scene_find_with_window(const bScreen *screen, const wmWindowManager *wm, struct wmWindow **r_window) +{ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (WM_window_get_active_screen(win) == screen) { + if (r_window) { + *r_window = win; + } + return WM_window_get_active_scene(win); + } + } + + BLI_assert(0); + return NULL; +} + + +Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm) +{ + return ED_screen_scene_find_with_window(screen, wm, NULL); +} + + +wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm) +{ + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (WM_window_get_active_screen(win) == screen) { + return win; + } + } + return NULL; +} |