diff options
Diffstat (limited to 'source/blender/editors/screen/screen_edit.c')
-rw-r--r-- | source/blender/editors/screen/screen_edit.c | 1431 |
1 files changed, 505 insertions, 926 deletions
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 2e8c5204b3d..b4c639e51b6 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_image.h" #include "BKE_global.h" +#include "BKE_icons.h" +#include "BKE_image.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,258 +67,39 @@ #include "UI_interface.h" -/* XXX actually should be not here... solve later */ -#include "wm_subwindow.h" - -#include "screen_intern.h" /* own module include */ - - -/* ******************* screen vert, edge, area managing *********************** */ - -static ScrVert *screen_addvert(bScreen *sc, short x, short y) -{ - ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert"); - sv->vec.x = x; - sv->vec.y = y; - - BLI_addtail(&sc->vertbase, sv); - return sv; -} - -static void sortscrvert(ScrVert **v1, ScrVert **v2) -{ - ScrVert *tmp; - - if (*v1 > *v2) { - tmp = *v1; - *v1 = *v2; - *v2 = tmp; - } -} - -static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2) -{ - ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge"); - - sortscrvert(&v1, &v2); - se->v1 = v1; - se->v2 = v2; - - BLI_addtail(&sc->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; +#include "WM_message.h" - 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) -{ - 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; - } -} - -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) -{ - ScrEdge *se; - int safety = U.widget_unit / 10; - - if (safety < 2) safety = 2; - - for (se = sc->edgebase.first; se; se = se->next) { - if (scredge_is_horizontal(se)) { - if (se->v1->vec.y > 0 && se->v1->vec.y < winsize_y - 1) { - short min, max; - min = MIN2(se->v1->vec.x, se->v2->vec.x); - max = MAX2(se->v1->vec.x, se->v2->vec.x); - - if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max) - return se; - } - } - else { - if (se->v1->vec.x > 0 && se->v1->vec.x < winsize_x - 1) { - short min, max; - min = MIN2(se->v1->vec.y, se->v2->vec.y); - max = MAX2(se->v1->vec.y, se->v2->vec.y); - - if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max) - return se; - } - } - } - - return NULL; -} +#include "DEG_depsgraph_query.h" +#include "screen_intern.h" /* own module include */ /* 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) { @@ -330,54 +112,18 @@ static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa) MEM_freeN(sa); } -/* return 0: no split possible */ -/* else return (integer) screencoordinate split point */ -static short testsplitpoint(ScrArea *sa, char dir, float fac) -{ - short x, y; - const short area_min_x = AREAMINX; - const short area_min_y = ED_area_headersize(); - - // area big enough? - if (dir == 'v' && (sa->v4->vec.x - sa->v1->vec.x <= 2 * area_min_x)) return 0; - if (dir == 'h' && (sa->v2->vec.y - sa->v1->vec.y <= 2 * area_min_y)) return 0; - - // to be sure - CLAMP(fac, 0.0f, 1.0f); - - if (dir == 'h') { - y = sa->v1->vec.y + fac * (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); - - 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; - } -} - -ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) +ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge) { ScrArea *newa = NULL; ScrVert *sv1, *sv2; short split; + rcti window_rect; if (sa == NULL) return NULL; - split = testsplitpoint(sa, dir, fac); + WM_window_rect_calc(win, &window_rect); + + split = screen_geom_find_area_split_point(sa, &window_rect, dir, fac); if (split == 0) return NULL; /* note regarding (fac > 0.5f) checks below. @@ -386,19 +132,19 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) if (dir == 'h') { /* new vertices */ - sv1 = screen_addvert(sc, sa->v1->vec.x, split); - sv2 = screen_addvert(sc, sa->v4->vec.x, split); + sv1 = screen_geom_vertex_add(sc, sa->v1->vec.x, split); + sv2 = screen_geom_vertex_add(sc, sa->v4->vec.x, split); /* new edges */ - screen_addedge(sc, sa->v1, sv1); - screen_addedge(sc, sv1, sa->v2); - screen_addedge(sc, sa->v3, sv2); - screen_addedge(sc, sv2, sa->v4); - screen_addedge(sc, sv1, sv2); + screen_geom_edge_add(sc, sa->v1, sv1); + screen_geom_edge_add(sc, sv1, sa->v2); + screen_geom_edge_add(sc, sa->v3, sv2); + screen_geom_edge_add(sc, sv2, sa->v4); + screen_geom_edge_add(sc, sv1, sv2); 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 +152,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; @@ -418,19 +164,19 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) } else { /* new vertices */ - sv1 = screen_addvert(sc, split, sa->v1->vec.y); - sv2 = screen_addvert(sc, split, sa->v2->vec.y); + sv1 = screen_geom_vertex_add(sc, split, sa->v1->vec.y); + sv2 = screen_geom_vertex_add(sc, split, sa->v2->vec.y); /* new edges */ - screen_addedge(sc, sa->v1, sv1); - screen_addedge(sc, sv1, sa->v4); - screen_addedge(sc, sa->v2, sv2); - screen_addedge(sc, sv2, sa->v3); - screen_addedge(sc, sv1, sv2); + screen_geom_edge_add(sc, sa->v1, sv1); + screen_geom_edge_add(sc, sv1, sa->v4); + screen_geom_edge_add(sc, sa->v2, sv2); + screen_geom_edge_add(sc, sv2, sa->v3); + screen_geom_edge_add(sc, sv1, sv2); 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 +184,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,46 +196,42 @@ 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_geom_vertex_add(sc, rect->xmin, rect->ymin); + sv2 = screen_geom_vertex_add(sc, rect->xmin, rect->ymax - 1); + sv3 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymax - 1); + sv4 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymin); - screen_addedge(sc, sv1, sv2); - screen_addedge(sc, sv2, sv3); - screen_addedge(sc, sv3, sv4); - screen_addedge(sc, sv4, sv1); + screen_geom_edge_add(sc, sv1, sv2); + screen_geom_edge_add(sc, sv2, sv3); + screen_geom_edge_add(sc, sv3, sv4); + screen_geom_edge_add(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; @@ -498,6 +240,8 @@ static void screen_copy(bScreen *to, bScreen *from) /* free contents of 'to', is from blenkernel screen.c */ BKE_screen_free(to); + to->flag = from->flag; + BLI_duplicatelist(&to->vertbase, &from->vertbase); BLI_duplicatelist(&to->edgebase, &from->edgebase); BLI_duplicatelist(&to->areabase, &from->areabase); @@ -511,7 +255,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 +276,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; } @@ -588,276 +341,53 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) if (dir == 0) { sa1->v1 = sa2->v1; sa1->v2 = sa2->v2; - screen_addedge(scr, sa1->v2, sa1->v3); - screen_addedge(scr, sa1->v1, sa1->v4); + screen_geom_edge_add(scr, sa1->v2, sa1->v3); + screen_geom_edge_add(scr, sa1->v1, sa1->v4); } else if (dir == 1) { sa1->v2 = sa2->v2; sa1->v3 = sa2->v3; - screen_addedge(scr, sa1->v1, sa1->v2); - screen_addedge(scr, sa1->v3, sa1->v4); + screen_geom_edge_add(scr, sa1->v1, sa1->v2); + screen_geom_edge_add(scr, sa1->v3, sa1->v4); } else if (dir == 2) { sa1->v3 = sa2->v3; sa1->v4 = sa2->v4; - screen_addedge(scr, sa1->v2, sa1->v3); - screen_addedge(scr, sa1->v1, sa1->v4); + screen_geom_edge_add(scr, sa1->v2, sa1->v3); + screen_geom_edge_add(scr, sa1->v1, sa1->v4); } else if (dir == 3) { sa1->v1 = sa2->v1; sa1->v4 = sa2->v4; - screen_addedge(scr, sa1->v1, sa1->v2); - screen_addedge(scr, sa1->v3, sa1->v4); + screen_geom_edge_add(scr, sa1->v1, sa1->v2); + screen_geom_edge_add(scr, sa1->v3, sa1->v4); } 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) -{ - ScrEdge *se; - ScrVert *sv; - int oneselected; - char dir; - - /* select connected, only in the right direction */ - /* 'dir' is the direction of EDGE */ - - if (edge->v1->vec.x == edge->v2->vec.x) dir = 'v'; - else dir = 'h'; - - sv = sc->vertbase.first; - while (sv) { - sv->flag = 0; - sv = sv->next; - } - - edge->v1->flag = 1; - edge->v2->flag = 1; - - oneselected = 1; - while (oneselected) { - se = sc->edgebase.first; - oneselected = 0; - while (se) { - if (se->v1->flag + se->v2->flag == 1) { - if (dir == 'h') { - if (se->v1->vec.y == se->v2->vec.y) { - se->v1->flag = se->v2->flag = 1; - oneselected = 1; - } - } - if (dir == 'v') { - if (se->v1->vec.x == se->v2->vec.x) { - se->v1->flag = se->v2->flag = 1; - oneselected = 1; - } - } - } - se = se->next; - } - } -} - -/* test if screen vertices should be scaled */ -static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) -{ - /* 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(); - ScrVert *sv = NULL; - ScrArea *sa; - int winsize_x_prev, winsize_y_prev; - float facx, facy, tempf, min[2], max[2]; - - /* calculate size */ - min[0] = min[1] = 20000.0f; - max[0] = max[1] = 0.0f; - - for (sv = sc->vertbase.first; sv; sv = sv->next) { - const float fv[2] = {(float)sv->vec.x, (float)sv->vec.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; - - -#ifdef USE_HEADER_SIZE_CLAMP -#define TEMP_BOTTOM 1 -#define TEMP_TOP 2 - - /* if the window's Y axis grows, clamp header sized areas */ - if (winsize_y_prev < winsize_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 - sa->v1->vec.y) < headery_margin_max) { - sa->temp = TEMP_TOP; - } - } - else if (sa->v1->vec.y == 0) { - if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) { - sa->temp = TEMP_BOTTOM; - } - } - } - } - } -#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); - - /* 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); - - 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); - } - } - - -#ifdef USE_HEADER_SIZE_CLAMP - if (winsize_y_prev < winsize_y) { /* growing? */ - for (sa = sc->areabase.first; sa; sa = sa->next) { - ScrEdge *se = NULL; - - if (sa->temp == 0) - continue; - - if (sa->v1 == sa->v2) - continue; - - /* adjust headery if verts are along the edge of window */ - if (sa->temp == TEMP_TOP) { - /* lower edge */ - const int yval = sa->v2->vec.y - headery_init; - se = screen_findedge(sc, sa->v4, sa->v1); - if (se != NULL) { - select_connected_scredge(sc, se); - } - for (sv = sc->vertbase.first; sv; sv = sv->next) { - if (sv != sa->v2 && sv != sa->v3) { - if (sv->flag) { - sv->vec.y = yval; - } - } - } - } - else { - /* upper edge */ - const int yval = sa->v1->vec.y + headery_init; - se = screen_findedge(sc, sa->v2, sa->v3); - if (se != NULL) { - select_connected_scredge(sc, se); - } - for (sv = sc->vertbase.first; sv; sv = sv->next) { - if (sv != sa->v1 && sv != sa->v4) { - if (sv->flag) { - sv->vec.y = yval; - } - } - } - } - } - } - -#undef USE_HEADER_SIZE_CLAMP -#undef TEMP_BOTTOM -#undef TEMP_TOP -#endif - - - /* test for collapsed areas. This could happen in some blender version... */ - /* ton: removed option now, it needs Context... */ - - /* make each window at least ED_area_headersize() high */ - for (sa = sc->areabase.first; sa; sa = sa->next) { - int headery = headery_init; - - /* adjust headery if verts are along the edge of window */ - if (sa->v1->vec.y > 0) - headery += U.pixelsize; - if (sa->v2->vec.y < winsize_y - 1) - 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); - if (se && sa->v1 != sa->v2) { - int yval; - - select_connected_scredge(sc, 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) { - if (sv->flag) { - sv->vec.y = yval; - } - } - } - } - } - } - -} /* ****************** 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->gizmo_map != NULL) { + if (WM_gizmomap_cursor_set(ar->gizmo_map, win)) { + return; + } + } ED_region_cursor_set(win, sa, ar); } return; @@ -869,23 +399,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 +437,37 @@ 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; - /* 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); + ED_screen_global_areas_refresh(win); + screen_refresh_headersizes(); - 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_geom_vertices_scale(win, screen); - 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 +476,20 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm) wmWindow *win; for (win = wm->windows.first; win; win = win->next) { + if (BKE_workspace_active_get(win->workspace_hook) == NULL) { + BKE_workspace_active_set(win->workspace_hook, bmain->workspaces.first); + } - if (win->screen == NULL) - win->screen = bmain->screen.first; + 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 +500,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 +518,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 +538,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 +552,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 +560,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 +590,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,10 +611,10 @@ 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_geom_find_active_scredge(win, screen, xy[0], xy[1]); if (actedge) { - if (scredge_is_horizontal(actedge)) + if (screen_geom_edge_is_horizontal(actedge)) WM_cursor_set(win, CURSOR_Y_MOVE); else WM_cursor_set(win, CURSOR_X_MOVE); @@ -1093,20 +627,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 +649,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); + /* cursors, for time being set always on edges, otherwise aregion doesn't switch */ + 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 +716,261 @@ 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_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin); + ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax); + ScrVert *top_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymax); + ScrVert *bottom_right = screen_geom_vertex_add_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_geom_edge_add_ex(area_map, bottom_left, top_left); + screen_geom_edge_add_ex(area_map, top_left, top_right); + screen_geom_edge_add_ex(area_map, top_right, bottom_right); + screen_geom_edge_add_ex(area_map, bottom_right, bottom_left); - 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; - } + return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype); +} + +static void screen_area_set_geometry_rect(ScrArea *sa, const rcti *rect) +{ + sa->v1->vec.x = rect->xmin; + sa->v1->vec.y = rect->ymin; + sa->v2->vec.x = rect->xmin; + sa->v2->vec.y = rect->ymax; + sa->v3->vec.x = rect->xmax; + sa->v3->vec.y = rect->ymax; + sa->v4->vec.x = rect->xmax; + sa->v4->vec.y = rect->ymin; +} + +static void screen_global_area_refresh( + wmWindow *win, bScreen *screen, + eSpace_Type space_type, GlobalAreaAlign align, const rcti *rect, + const short height_cur, const short height_min, const short height_max) +{ + ScrArea *area; + + for (area = win->global_areas.areabase.first; area; area = area->next) { + if (area->spacetype == space_type) { + break; } } - /* check for valid winid */ - if (sc->winid != 0 && sc->winid != win->winid) { - return false; + if (area) { + screen_area_set_geometry_rect(area, rect); } + else { + 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)); - if (oldscreen != sc) { - wmTimer *wt = oldscreen->animtimer; - ScrArea *sa; - Scene *oldscene = oldscreen->scene; + area->regionbase = slink->regionbase; - /* remove handlers referencing areas in old screen */ - for (sa = oldscreen->areabase.first; sa; sa = sa->next) { - WM_event_remove_area_handler(&win->modalhandlers, sa); - } + BLI_addhead(&area->spacedata, slink); + BLI_listbase_clear(&slink->regionbase); - /* we put timer to sleep, so screen_exit has to think there's no timer */ - oldscreen->animtimer = NULL; - if (wt) { - WM_event_timer_sleep(wm, win, wt, true); - } + /* Data specific to global areas. */ + area->global = MEM_callocN(sizeof(*area->global), __func__); + area->global->size_max = height_max; + area->global->size_min = height_min; + area->global->align = align; + } - ED_screen_exit(C, win, oldscreen); + if (area->global->cur_fixed_height != height_cur) { + /* Refresh layout if size changes. */ + area->global->cur_fixed_height = height_cur; + screen->do_refresh = true; + } +} - /* Same scene, "transfer" playback to new screen. */ - if (wt) { - if (oldscene == sc->scene) { - sc->animtimer = wt; +static void screen_global_topbar_area_refresh(wmWindow *win, bScreen *screen) +{ + const short size_min = HEADERY; + const short size_max = 2.25 * HEADERY; + const short size = (screen->flag & SCREEN_COLLAPSE_TOPBAR) ? size_min : size_max; + 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_max; + + screen_global_area_refresh(win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size_min, size_max); +} + +static void screen_global_statusbar_area_refresh(wmWindow *win, bScreen *screen) +{ + const short size_min = 1; + const short size_max = 0.8f * HEADERY; + const short size = (screen->flag & SCREEN_COLLAPSE_STATUSBAR) ? size_min : size_max; + 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_max; + + screen_global_area_refresh(win, screen, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size, size_min, size_max); +} + +void ED_screen_global_areas_sync(wmWindow *win) +{ + /* Update screen flags from height in window, this is weak and perhaps + * global areas should just become part of the screen instead. */ + bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + + screen->flag &= ~(SCREEN_COLLAPSE_STATUSBAR | SCREEN_COLLAPSE_TOPBAR); + + for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) { + if (area->global->cur_fixed_height == area->global->size_min) { + if (area->spacetype == SPACE_TOPBAR) { + screen->flag |= SCREEN_COLLAPSE_TOPBAR; } - /* Else, stop playback. */ - else { - oldscreen->animtimer = wt; - ED_screen_animation_play(C, 0, 0); + else if (area->spacetype == SPACE_STATUSBAR) { + screen->flag |= SCREEN_COLLAPSE_STATUSBAR; } } + } +} - 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); +void ED_screen_global_areas_refresh(wmWindow *win) +{ + /* Don't create global area for child and temporary windows. */ + bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook); + if ((win->parent != NULL) || screen->temp) { + if (win->global_areas.areabase.first) { + screen->do_refresh = true; + BKE_screen_area_map_free(&win->global_areas); } + return; + } + + screen_global_topbar_area_refresh(win, screen); + screen_global_statusbar_area_refresh(win, screen); +} - /* 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); + +/* -------------------------------------------------------------------- */ +/* 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 true; + return screen; } -static bool ed_screen_used(wmWindowManager *wm, bScreen *sc) +/** + * \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) { - wmWindow *win; + /* validate screen, it's called with notifier reference */ + if (BLI_findindex(&bmain->screen, screen_new) == -1) { + return NULL; + } - for (win = wm->windows.first; win; win = win->next) { - if (win->screen == sc) { - return true; + if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) { + screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new); + } + + /* check for valid winid */ + if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) { + return NULL; + } + + if (screen_old != screen_new) { + wmTimer *wt = screen_old->animtimer; + + /* remove handlers referencing areas in old screen */ + for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) { + WM_event_remove_area_handler(&win->modalhandlers, sa); } - if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) { - ScrArea *sa = win->screen->areabase.first; - if (sa->full == sc) { - return true; - } + /* we put timer to sleep, so screen_exit has to think there's no timer */ + screen_old->animtimer = NULL; + if (wt) { + WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true); + } + ED_screen_exit(C, win, screen_old); + + /* Same scene, "transfer" playback to new screen. */ + if (wt) { + screen_new->animtimer = wt; } + + return screen_new; } - return false; + return NULL; } -/* only call outside of area/region loops */ -bool ED_screen_delete(bContext *C, bScreen *sc) +void screen_change_update(bContext *C, wmWindow *win, bScreen *sc) { - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - bScreen *newsc; + 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); - /* don't allow deleting temp fullscreens for now */ - if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) { - return false; - } + CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */ - /* 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 */ + ED_screen_refresh(CTX_wm_manager(C), win); - for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev) - if (!ed_screen_used(wm, newsc) && !newsc->temp) - break; + 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); - if (!newsc) { - for (newsc = sc->id.next; newsc; newsc = newsc->id.next) - if (!ed_screen_used(wm, newsc) && !newsc->temp) - break; - } + /* makes button hilites work */ + WM_event_add_mousemove(C); +} - if (!newsc) { - return false; - } - ED_screen_set(C, newsc); +/** + * \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); + wmWindow *win = CTX_wm_window(C); + bScreen *screen_old = CTX_wm_screen(C); + bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win); + + 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); - 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,104 +994,49 @@ 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_scene_change(bContext *C, wmWindow *win, Scene *scene) { - Main *bmain = CTX_data_main(C); - bScreen *sc; - - if (screen == NULL) - return; +#if 0 + ViewLayer *view_layer_old = WM_window_get_active_view_layer(win); +#endif - if (ed_screen_used(CTX_wm_manager(C), screen)) { - ED_object_editmode_exit(C, EM_FREEDATA); + /* Switch scene. */ + win->scene = scene; + if (CTX_wm_window(C) == win) { + CTX_data_scene_set(C, scene); } - 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; - } + /* Ensure the view layer name is updated. */ + WM_window_ensure_active_view_layer(win); + ViewLayer *view_layer = WM_window_get_active_view_layer(win); - } +#if 0 + /* Mode Syncing. */ + if (view_layer_old) { + WorkSpace *workspace = CTX_wm_workspace(C); + Object *obact_new = OBACT(view_layer); + UNUSED_VARS(obact_new); + eObjectMode object_mode_old = workspace->object_mode; + Object *obact_old = OBACT(view_layer_old); + UNUSED_VARS(obact_old, object_mode_old); } +#endif - // 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; + /* Update 3D view cameras. */ + const bScreen *screen = WM_window_get_active_screen(win); + 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, view_layer, sa, v3d); } } } - - 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; - - /* kill running jobs */ - wmWindowManager *wm = CTX_wm_manager(C); - WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_ANY); - - 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) { @@ -1481,18 +1044,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); @@ -1575,6 +1127,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; @@ -1591,16 +1144,19 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s } } - /* prevent hanging header prints */ - ED_area_headerprint(sa, NULL); + /* prevent hanging status prints */ + ED_area_status_text(sa, NULL); + ED_workspace_status_text(C, NULL); } 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; + sc->flag = oldscreen->flag; /* find old area to restore from */ ScrArea *fullsa = NULL; @@ -1612,10 +1168,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) { @@ -1625,6 +1179,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; @@ -1637,9 +1195,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. @@ -1649,17 +1207,24 @@ 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; + sc->flag = oldscreen->flag; /* timer */ sc->animtimer = oldscreen->animtimer; @@ -1667,51 +1232,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, RGN_TYPE_NAV_BAR)) { 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 */ @@ -1798,7 +1347,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; @@ -1846,13 +1395,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); @@ -1861,19 +1407,16 @@ 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); } + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); } #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) @@ -1894,11 +1437,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) { @@ -1973,3 +1515,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; +} |