diff options
Diffstat (limited to 'source/blender/editors/screen')
-rw-r--r-- | source/blender/editors/screen/CMakeLists.txt | 4 | ||||
-rw-r--r-- | source/blender/editors/screen/area.c | 628 | ||||
-rw-r--r-- | source/blender/editors/screen/glutil.c | 764 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_context.c | 181 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_draw.c | 316 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_edit.c | 534 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_intern.h | 13 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_ops.c | 324 | ||||
-rw-r--r-- | source/blender/editors/screen/screendump.c | 31 | ||||
-rw-r--r-- | source/blender/editors/screen/workspace_edit.c | 524 | ||||
-rw-r--r-- | source/blender/editors/screen/workspace_layout_edit.c | 197 |
11 files changed, 1961 insertions, 1555 deletions
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index 43e044b613a..29b9971eabb 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -23,8 +23,10 @@ set(INC ../../blenfont ../../blenkernel ../../blenlib + ../../blenloader ../../blentranslation ../../bmesh + ../../depsgraph ../../gpu ../../imbuf ../../makesdna @@ -46,6 +48,8 @@ set(SRC screen_edit.c screen_ops.c screendump.c + workspace_edit.c + workspace_layout_edit.c screen_intern.h ) diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index fc0922c7b7c..ac577375a31 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -41,24 +41,27 @@ #include "BLI_utildefines.h" #include "BLI_linklist_stack.h" - #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_workspace.h" #include "RNA_access.h" #include "RNA_types.h" #include "WM_api.h" #include "WM_types.h" -#include "wm_subwindow.h" +#include "WM_message.h" #include "ED_screen.h" #include "ED_screen_types.h" #include "ED_space_api.h" -#include "BIF_gl.h" -#include "BIF_glutil.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_draw.h" + #include "BLF_api.h" #include "IMB_imbuf.h" @@ -71,7 +74,7 @@ #include "screen_intern.h" -extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */ +extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]); /* xxx temp */ /* general area and region code */ @@ -87,23 +90,32 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) /* set transp line */ glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GWN_PRIM_LINE_STRIP, 5); /* right */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax); + immAttrib4ub(color, 0, 0, 0, 30); + immVertex2f(pos, rect.xmax, rect.ymax); + immVertex2f(pos, rect.xmax, rect.ymin); /* bottom */ - glColor4ub(0, 0, 0, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin); + immVertex2f(pos, rect.xmin, rect.ymin); - /* top */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax); - /* left */ - glColor4ub(255, 255, 255, 30); - sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax); + immAttrib4ub(color, 255, 255, 255, 30); + immVertex2f(pos, rect.xmin, rect.ymax); + + /* top */ + immVertex2f(pos, rect.xmax, rect.ymax); + + immEnd(); + immUnbindProgram(); glDisable(GL_BLEND); } @@ -111,11 +123,11 @@ static void region_draw_emboss(const ARegion *ar, const rcti *scirct) void ED_region_pixelspace(ARegion *ar) { wmOrtho2_region_pixelspace(ar); - glLoadIdentity(); + gpuLoadIdentity(); } /* only exported for WM */ -void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note) +void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note, const Scene *scene) { /* generic notes first */ switch (note->category) { @@ -129,15 +141,15 @@ void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note } if (ar->type && ar->type->listener) - ar->type->listener(sc, sa, ar, note); + ar->type->listener(sc, sa, ar, note, scene); } /* only exported for WM */ -void ED_area_do_listen(bScreen *sc, ScrArea *sa, wmNotifier *note) +void ED_area_do_listen(bScreen *sc, ScrArea *sa, wmNotifier *note, Scene *scene, WorkSpace *workspace) { /* no generic notes? */ if (sa->type && sa->type->listener) { - sa->type->listener(sc, sa, note); + sa->type->listener(sc, sa, note, scene, workspace); } } @@ -206,15 +218,27 @@ static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, f if (G.debug_value == 1) { rcti click_rect; float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC; - char alpha_debug = 255 * alpha; + unsigned char alpha_debug = 255 * alpha; BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size); - glColor4ub(255, 0, 0, alpha_debug); - fdrawbox(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); - glColor4ub(0, 255, 255, alpha_debug); - fdrawline(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); - fdrawline(click_rect.xmin, click_rect.ymax, click_rect.xmax, click_rect.ymin); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + immAttrib4ub(color, 255, 0, 0, alpha_debug); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + imm_draw_box_wire_2d(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax); + + immAttrib4ub(color, 0, 255, 255, alpha_debug); + immBegin(GWN_PRIM_LINES, 4); + immVertex2f(pos, click_rect.xmin, click_rect.ymin); + immVertex2f(pos, click_rect.xmax, click_rect.ymax); + immVertex2f(pos, click_rect.xmin, click_rect.ymax); + immVertex2f(pos, click_rect.xmax, click_rect.ymin); + immEnd(); + + immUnbindProgram(); } } @@ -229,69 +253,96 @@ static void area_draw_azone(short x1, short y1, short x2, short y2) dx = copysign(ceilf(0.3f * abs(dx)), dx); dy = copysign(ceilf(0.3f * abs(dy)), dy); - glEnable(GL_BLEND); glEnable(GL_LINE_SMOOTH); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GWN_PRIM_LINES, 12); + + immAttrib4ub(col, 255, 255, 255, 180); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y1); + + immAttrib4ub(col, 255, 255, 255, 130); + immVertex2f(pos, x1, y2 - dy); + immVertex2f(pos, x2 - dx, y1); + + immAttrib4ub(col, 255, 255, 255, 80); + immVertex2f(pos, x1, y2 - 2 * dy); + immVertex2f(pos, x2 - 2 * dx, y1); - glColor4ub(255, 255, 255, 180); - fdrawline(x1, y2, x2, y1); - glColor4ub(255, 255, 255, 130); - fdrawline(x1, y2 - dy, x2 - dx, y1); - glColor4ub(255, 255, 255, 80); - fdrawline(x1, y2 - 2 * dy, x2 - 2 * dx, y1); - - glColor4ub(0, 0, 0, 210); - fdrawline(x1, y2 + 1, x2 + 1, y1); - glColor4ub(0, 0, 0, 180); - fdrawline(x1, y2 - dy + 1, x2 - dx + 1, y1); - glColor4ub(0, 0, 0, 150); - fdrawline(x1, y2 - 2 * dy + 1, x2 - 2 * dx + 1, y1); + immAttrib4ub(col, 0, 0, 0, 210); + immVertex2f(pos, x1, y2 + 1); + immVertex2f(pos, x2 + 1, y1); + + immAttrib4ub(col, 0, 0, 0, 180); + immVertex2f(pos, x1, y2 - dy + 1); + immVertex2f(pos, x2 - dx + 1, y1); + + immAttrib4ub(col, 0, 0, 0, 150); + immVertex2f(pos, x1, y2 - 2 * dy + 1); + immVertex2f(pos, x2 - 2 * dx + 1, y1); + + immEnd(); + immUnbindProgram(); glDisable(GL_LINE_SMOOTH); - glDisable(GL_BLEND); } static void region_draw_azone_icon(AZone *az) { - GLUquadricObj *qobj = NULL; - short midx = az->x1 + (az->x2 - az->x1) / 2; - short midy = az->y1 + (az->y2 - az->y1) / 2; - - qobj = gluNewQuadric(); - - glPushMatrix(); - glTranslatef(midx, midy, 0.0); - - /* outlined circle */ - glEnable(GL_LINE_SMOOTH); + float midx = az->x1 + (az->x2 - az->x1) * 0.5f; + float midy = az->y1 + (az->y2 - az->y1) * 0.5f; - glColor4f(1.f, 1.f, 1.f, 0.8f); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - gluQuadricDrawStyle(qobj, GLU_FILL); - gluDisk(qobj, 0.0, 4.25f, 16, 1); + /* outlined circle */ + GPU_enable_program_point_size(); /* TODO: make a fixed-size shader to avoid this */ + immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA); + immUniformColor4f(1.0f, 1.0f, 1.0f, 0.8f); + immUniform4f("outlineColor", 0.2f, 0.2f, 0.2f, 0.9f); + immUniform1f("outlineWidth", 1.0f); + immUniform1f("size", 9.5f); + immBegin(GWN_PRIM_POINTS, 1); + immVertex2f(pos, midx, midy); + immEnd(); + immUnbindProgram(); + GPU_disable_program_point_size(); - glColor4f(0.2f, 0.2f, 0.2f, 0.9f); - - gluQuadricDrawStyle(qobj, GLU_SILHOUETTE); - gluDisk(qobj, 0.0, 4.25f, 16, 1); - - glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); - gluDeleteQuadric(qobj); - /* + */ - sdrawline(midx, midy - 2, midx, midy + 3); - sdrawline(midx - 2, midy, midx + 3, midy); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.2f, 0.2f, 0.2f, 0.9f); + immBegin(GWN_PRIM_LINES, 4); + immVertex2f(pos, midx, midy - 2); + immVertex2f(pos, midx, midy + 3); + immVertex2f(pos, midx - 2, midy); + immVertex2f(pos, midx + 3, midy); + immEnd(); + immUnbindProgram(); } static void draw_azone_plus(float x1, float y1, float x2, float y2) { float width = 0.1f * U.widget_unit; float pad = 0.2f * U.widget_unit; - - glRectf((x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad); - glRectf(x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f); - glRectf((x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + glEnable(GL_BLEND); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(0.8f, 0.8f, 0.8f, 0.4f); + + immRectf(pos, (x1 + x2 - width) * 0.5f, y1 + pad, (x1 + x2 + width) * 0.5f, y2 - pad); + immRectf(pos, x1 + pad, (y1 + y2 - width) * 0.5f, (x1 + x2 - width) * 0.5f, (y1 + y2 + width) * 0.5f); + immRectf(pos, (x1 + x2 + width) * 0.5f, (y1 + y2 - width) * 0.5f, x2 - pad, (y1 + y2 + width) * 0.5f); + + immUnbindProgram(); + glDisable(GL_BLEND); } static void region_draw_azone_tab_plus(AZone *az) @@ -314,54 +365,41 @@ static void region_draw_azone_tab_plus(AZone *az) break; } - glColor4f(0.05f, 0.05f, 0.05f, 0.4f); - UI_draw_roundbox((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); - - glEnable(GL_BLEND); + float color[4] = {0.05f, 0.05f, 0.05f, 0.4f}; + UI_draw_roundbox_aa(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, color); - glColor4f(0.8f, 0.8f, 0.8f, 0.4f); draw_azone_plus((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2); - - glDisable(GL_BLEND); } static void region_draw_azone_tab(AZone *az) { - float col[3]; + float col[4], black[4] = {0.0f, 0.0f, 0.0f, 0.5f}; glEnable(GL_BLEND); UI_GetThemeColor3fv(TH_HEADER, col); - glColor4f(col[0], col[1], col[2], 0.5f); - + col[3] = 0.5f; + /* add code to draw region hidden as 'too small' */ switch (az->edge) { case AE_TOP_TO_BOTTOMRIGHT: - UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT | UI_RB_ALPHA); - - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f); + UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT); + UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_aa(false, (float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f, black); break; case AE_BOTTOM_TO_TOPLEFT: - UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA); - - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f); + UI_draw_roundbox_corner_set(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT); + UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_aa(false, (float)az->x1, 0.3f + (float)az->y1, (float)az->x2, 0.3f + (float)az->y2, 4.0f, black); break; case AE_LEFT_TO_TOPRIGHT: - UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT | UI_RB_ALPHA); - - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); + UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT); + UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_aa(false, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, black); break; case AE_RIGHT_TO_TOPLEFT: - UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT | UI_RB_ALPHA); - - UI_draw_roundbox_shade_x(GL_POLYGON, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f); - glColor4ub(0, 0, 0, 255); - UI_draw_roundbox_unfilled((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f); + UI_draw_roundbox_corner_set(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); + UI_draw_roundbox_shade_x(true, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, -0.3f, 0.05f, col); + UI_draw_roundbox_aa(false, (float)az->x1, (float)az->y1, (float)az->x2, (float)az->y2, 4.0f, black); break; } @@ -372,24 +410,24 @@ static void region_draw_azone_tria(AZone *az) { glEnable(GL_BLEND); //UI_GetThemeColor3fv(TH_HEADER, col); - glColor4f(0.0f, 0.0f, 0.0f, 0.35f); + float color[4] = {0.0f, 0.0f, 0.0f, 0.35f}; /* add code to draw region hidden as 'too small' */ switch (az->edge) { case AE_TOP_TO_BOTTOMRIGHT: - ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y1, (float)(az->x1 + az->x2) / 2, (float)az->y2); + ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x2, (float)az->y1, (float)(az->x1 + az->x2) / 2, (float)az->y2, color); break; case AE_BOTTOM_TO_TOPLEFT: - ui_draw_anti_tria((float)az->x1, (float)az->y2, (float)az->x2, (float)az->y2, (float)(az->x1 + az->x2) / 2, (float)az->y1); + ui_draw_anti_tria((float)az->x1, (float)az->y2, (float)az->x2, (float)az->y2, (float)(az->x1 + az->x2) / 2, (float)az->y1, color); break; case AE_LEFT_TO_TOPRIGHT: - ui_draw_anti_tria((float)az->x2, (float)az->y1, (float)az->x2, (float)az->y2, (float)az->x1, (float)(az->y1 + az->y2) / 2); + ui_draw_anti_tria((float)az->x2, (float)az->y1, (float)az->x2, (float)az->y2, (float)az->x1, (float)(az->y1 + az->y2) / 2, color); break; case AE_RIGHT_TO_TOPLEFT: - ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x1, (float)az->y2, (float)az->x2, (float)(az->y1 + az->y2) / 2); + ui_draw_anti_tria((float)az->x1, (float)az->y1, (float)az->x1, (float)az->y2, (float)az->x2, (float)(az->y1 + az->y2) / 2, color); break; } @@ -411,10 +449,10 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar) glLineWidth(1.0f); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - glPushMatrix(); - glTranslatef(-ar->winrct.xmin, -ar->winrct.ymin, 0.0f); + gpuPushMatrix(); + gpuTranslate2f(-ar->winrct.xmin, -ar->winrct.ymin); for (az = sa->actionzones.first; az; az = az->next) { /* test if action zone is over this region */ @@ -451,28 +489,38 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar) } } - glPopMatrix(); + gpuPopMatrix(); glDisable(GL_BLEND); } -/* only exported for WM */ -/* makes region ready for drawing, sets pixelspace */ -void ED_region_set(const bContext *C, ARegion *ar) +/* Follow wmMsgNotifyFn spec */ +void ED_region_do_msg_notify_tag_redraw( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) { - wmWindow *win = CTX_wm_window(C); - ScrArea *sa = CTX_wm_area(C); - - ar->drawrct = ar->winrct; - - /* note; this sets state, so we can use wmOrtho and friends */ - wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, true); - - UI_SetTheme(sa ? sa->spacetype : 0, ar->type ? ar->type->regionid : 0); - - ED_region_pixelspace(ar); -} + ARegion *ar = msg_val->owner; + ED_region_tag_redraw(ar); + /* This avoids _many_ situations where header/properties control display settings. + * the common case is space properties in the header */ + if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_UI)) { + while (ar && ar->prev) { + ar = ar->prev; + } + for (; ar; ar = ar->next) { + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS)) { + ED_region_tag_redraw(ar); + } + } + } +} +/* Follow wmMsgNotifyFn spec */ +void ED_area_do_msg_notify_tag_refresh( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + ScrArea *sa = msg_val->user_data; + ED_area_tag_refresh(sa); +} /* only exported for WM */ void ED_region_do_draw(bContext *C, ARegion *ar) @@ -480,27 +528,15 @@ void ED_region_do_draw(bContext *C, ARegion *ar) wmWindow *win = CTX_wm_window(C); ScrArea *sa = CTX_wm_area(C); ARegionType *at = ar->type; - bool scissor_pad; /* see BKE_spacedata_draw_locks() */ if (at->do_lock) return; - /* if no partial draw rect set, full rect */ - if (ar->drawrct.xmin == ar->drawrct.xmax) { - ar->drawrct = ar->winrct; - scissor_pad = true; - } - else { - /* extra clip for safety */ - BLI_rcti_isect(&ar->winrct, &ar->drawrct, &ar->drawrct); - scissor_pad = false; - } - ar->do_draw |= RGN_DRAWING; - /* note; this sets state, so we can use wmOrtho and friends */ - wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, scissor_pad); + /* Set viewport, scissor, ortho and ar->drawrct. */ + wmPartialViewport(&ar->drawrct, &ar->winrct, &ar->drawrct); wmOrtho2_region_pixelspace(ar); @@ -511,7 +547,7 @@ void ED_region_do_draw(bContext *C, ARegion *ar) UI_ThemeClearColor(TH_HEADER); glClear(GL_COLOR_BUFFER_BIT); - UI_ThemeColor(TH_TEXT); + UI_FontThemeColor(BLF_default(), TH_TEXT); BLF_draw_default(UI_UNIT_X, 0.4f * UI_UNIT_Y, 0.0f, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX); } else if (at->draw) { @@ -528,9 +564,13 @@ void ED_region_do_draw(bContext *C, ARegion *ar) /* for debugging unneeded area redraws and partial redraw */ #if 0 glEnable(GL_BLEND); - glColor4f(drand48(), drand48(), drand48(), 0.1f); - glRectf(ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin, + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4f(drand48(), drand48(), drand48(), 0.1f); + immRectf(pos, ar->drawrct.xmin - ar->winrct.xmin, ar->drawrct.ymin - ar->winrct.ymin, ar->drawrct.xmax - ar->winrct.xmin, ar->drawrct.ymax - ar->winrct.ymin); + immUnbindProgram(); glDisable(GL_BLEND); #endif @@ -539,12 +579,45 @@ void ED_region_do_draw(bContext *C, ARegion *ar) UI_blocklist_free_inactive(C, &ar->uiblocks); if (sa) { + const bScreen *screen = WM_window_get_active_screen(win); + /* disable emboss when the area is full, * unless we need to see division between regions (quad-split for eg) */ - if (((win->screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) { + if (((screen->state == SCREENFULL) && (ar->alignment == RGN_ALIGN_NONE)) == 0) { region_draw_emboss(ar, &ar->winrct); } } + + /* We may want to detach message-subscriptions from drawing. */ + { + WorkSpace *workspace = CTX_wm_workspace(C); + wmWindowManager *wm = CTX_wm_manager(C); + bScreen *screen = WM_window_get_active_screen(win); + Scene *scene = CTX_data_scene(C); + struct wmMsgBus *mbus = wm->message_bus; + WM_msgbus_clear_by_owner(mbus, ar); + + /* Cheat, always subscribe to this space type properties. + * + * This covers most cases and avoids copy-paste similar code for each space type. + */ + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) { + SpaceLink *sl = sa->spacedata.first; + + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__); + } + + ED_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus); + } } /* ********************************** @@ -655,7 +728,7 @@ void ED_area_headerprint(ScrArea *sa, const char *str) /* ************************************************************ */ -static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa) +static void area_azone_initialize(wmWindow *win, const bScreen *screen, ScrArea *sa) { AZone *az; @@ -1315,7 +1388,9 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti * must be minimum '4' */ } else { - if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) { + const bScreen *screen = WM_window_get_active_screen(win); + + if (ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) { region_azone_add(sa, ar, alignment, false); } else { @@ -1348,24 +1423,14 @@ static void area_calc_totrct(ScrArea *sa, int sizex, int sizey) /* used for area initialize below */ -static void region_subwindow(wmWindow *win, ARegion *ar, bool activate) +static void region_subwindow(ARegion *ar) { bool hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) != 0; if ((ar->alignment & RGN_SPLIT_PREV) && ar->prev) hidden = hidden || (ar->prev->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)); - if (hidden) { - if (ar->swinid) - wm_subwindow_close(win, ar->swinid); - ar->swinid = 0; - } - else if (ar->swinid == 0) { - ar->swinid = wm_subwindow_open(win, &ar->winrct, activate); - } - else { - wm_subwindow_position(win, ar->swinid, &ar->winrct, activate); - } + ar->visible = !hidden; } static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *handlers, int flag) @@ -1439,6 +1504,7 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand /* called in screen_refresh, or screens_init, also area size changes */ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) { + const bScreen *screen = WM_window_get_active_screen(win); ARegion *ar; rcti rect; @@ -1457,7 +1523,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) area_calc_totrct(sa, WM_window_pixels_x(win), WM_window_pixels_y(win)); /* clear all azones, add the area triange widgets */ - area_azone_initialize(win, win->screen, sa); + area_azone_initialize(win, screen, sa); /* region rect sizes */ rect = sa->totrct; @@ -1471,14 +1537,15 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa) /* region windows, default and own handlers */ for (ar = sa->regionbase.first; ar; ar = ar->next) { - region_subwindow(win, ar, false); + region_subwindow(ar); - if (ar->swinid) { + if (ar->visible) { /* default region handlers */ ed_default_handlers(wm, sa, &ar->handlers, ar->type->keymapflag); /* own handlers */ - if (ar->type->init) + if (ar->type->init) { ar->type->init(wm, ar); + } } else { /* prevent uiblocks to run */ @@ -1499,22 +1566,16 @@ static void region_update_rect(ARegion *ar) /** * Call to move a popup window (keep OpenGL context free!) */ -void ED_region_update_rect(bContext *C, ARegion *ar) +void ED_region_update_rect(bContext *UNUSED(C), ARegion *ar) { - wmWindow *win = CTX_wm_window(C); - - wm_subwindow_rect_set(win, ar->swinid, &ar->winrct); - region_update_rect(ar); } /* externally called for floating regions like menus */ -void ED_region_init(bContext *C, ARegion *ar) +void ED_region_init(bContext *UNUSED(C), ARegion *ar) { -// ARegionType *at = ar->type; - /* refresh can be called before window opened */ - region_subwindow(CTX_wm_window(C), ar, false); + region_subwindow(ar); region_update_rect(ar); } @@ -1763,6 +1824,7 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco) void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical) { + const WorkSpace *workspace = CTX_wm_workspace(C); ScrArea *sa = CTX_wm_area(C); uiStyle *style = UI_style_get_dpi(); uiBlock *block; @@ -1813,6 +1875,11 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c continue; } + /* If we're tagged, only use compatible. */ + if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) { + continue; + } + /* draw panel */ if (pt->draw && (!pt->poll || pt->poll(C, pt))) { BLI_SMALLSTACK_PUSH(pt_stack, pt); @@ -1972,8 +2039,12 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c /* view should be in pixelspace */ UI_view2d_view_restore(C); glEnable(GL_BLEND); - UI_ThemeColor4((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); - glRecti(0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK); + immRecti(pos, 0, 0, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct) + 1); + immUnbindProgram(); glDisable(GL_BLEND); } else { @@ -2077,22 +2148,37 @@ int ED_area_headersize(void) return (int)(HEADERY * UI_DPI_FAC); } -void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], const bool full_redraw) +void ED_region_info_draw_multiline(ARegion *ar, const char *text_array[], float fill_color[4], const bool full_redraw) { const int header_height = UI_UNIT_Y; uiStyle *style = UI_style_get_dpi(); int fontid = style->widget.uifont_id; GLint scissor[4]; rcti rect; + int num_lines = 0; /* background box */ ED_region_visible_rect(ar, &rect); - rect.ymin = BLI_rcti_size_y(&ar->winrct) - header_height; - /* box fill entire width or just around text */ - if (!full_redraw) - rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, text, BLF_DRAW_STR_DUMMY_MAX) + 1.2f * U.widget_unit); + /* Box fill entire width or just around text. */ + if (!full_redraw) { + const char **text = &text_array[0]; + while (*text) { + rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, *text, BLF_DRAW_STR_DUMMY_MAX) + 1.2f * U.widget_unit); + text++; + num_lines++; + } + } + /* Just count the line number. */ + else { + const char **text = &text_array[0]; + while (*text) { + text++; + num_lines++; + } + } + rect.ymin = BLI_rcti_size_y(&ar->winrct) - header_height * num_lines; rect.ymax = BLI_rcti_size_y(&ar->winrct); /* setup scissor */ @@ -2101,18 +2187,29 @@ void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], con BLI_rcti_size_x(&rect) + 1, BLI_rcti_size_y(&rect) + 1); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4fv(fill_color); - glRecti(rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(fill_color); + immRecti(pos, rect.xmin, rect.ymin, rect.xmax + 1, rect.ymax + 1); + immUnbindProgram(); glDisable(GL_BLEND); /* text */ - UI_ThemeColor(TH_TEXT_HI); + UI_FontThemeColor(fontid, TH_TEXT_HI); BLF_clipping(fontid, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(fontid, BLF_CLIPPING); - BLF_position(fontid, rect.xmin + 0.6f * U.widget_unit, rect.ymin + 0.3f * U.widget_unit, 0.0f); - - BLF_draw(fontid, text, BLF_DRAW_STR_DUMMY_MAX); + int offset = num_lines - 1; + { + const char **text = &text_array[0]; + while (*text) { + BLF_position(fontid, rect.xmin + 0.6f * U.widget_unit, rect.ymin + 0.3f * U.widget_unit + offset * header_height, 0.0f); + BLF_draw(fontid, *text, BLF_DRAW_STR_DUMMY_MAX); + text++; + offset--; + } + } BLF_disable(fontid, BLF_CLIPPING); @@ -2120,6 +2217,11 @@ void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], con glScissor(scissor[0], scissor[1], scissor[2], scissor[3]); } +void ED_region_info_draw(ARegion *ar, const char *text, float fill_color[4], const bool full_redraw) +{ + ED_region_info_draw_multiline(ar, (const char *[2]){text, NULL}, fill_color, full_redraw); +} + #define MAX_METADATA_STR 1024 static const char *meta_data_list[] = @@ -2288,11 +2390,11 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, return; /* find window pixel coordinates of origin */ - glPushMatrix(); + gpuPushMatrix(); /* offset and zoom using ogl */ - glTranslatef(x, y, 0.0f); - glScalef(zoomx, zoomy, 1.0f); + gpuTranslate2f(x, y); + gpuScale2f(zoomx, zoomy); BLF_size(blf_mono_font, style->widgetlabel.points * 1.5f * U.pixelsize, U.dpi); @@ -2302,17 +2404,20 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, box_y = metadata_box_height_get(ibuf, blf_mono_font, true); if (box_y) { - UI_ThemeColor(TH_METADATA_BG); - /* set up rect */ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymax, frame->ymax + box_y); /* draw top box */ - glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(blf_mono_font, BLF_CLIPPING); - UI_ThemeColor(TH_METADATA_TEXT); + UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); metadata_draw_imbuf(ibuf, &rect, blf_mono_font, true); BLF_disable(blf_mono_font, BLF_CLIPPING); @@ -2324,23 +2429,26 @@ void ED_region_image_metadata_draw(int x, int y, ImBuf *ibuf, const rctf *frame, box_y = metadata_box_height_get(ibuf, blf_mono_font, false); if (box_y) { - UI_ThemeColor(TH_METADATA_BG); - /* set up box rect */ BLI_rctf_init(&rect, frame->xmin, frame->xmax, frame->ymin - box_y, frame->ymin); /* draw top box */ - glRectf(rect.xmin, rect.ymin, rect.xmax, rect.ymax); + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_METADATA_BG); + immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + immUnbindProgram(); BLF_clipping(blf_mono_font, rect.xmin, rect.ymin, rect.xmax, rect.ymax); BLF_enable(blf_mono_font, BLF_CLIPPING); - UI_ThemeColor(TH_METADATA_TEXT); + UI_FontThemeColor(blf_mono_font, TH_METADATA_TEXT); metadata_draw_imbuf(ibuf, &rect, blf_mono_font, false); BLF_disable(blf_mono_font, BLF_CLIPPING); } - glPopMatrix(); + gpuPopMatrix(); } void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) @@ -2350,11 +2458,16 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) int x1, y1, x2, y2; /* the image is located inside (0, 0), (1, 1) as set by view2d */ - UI_ThemeColorShade(TH_BACK, 20); - UI_view2d_view_to_region(&ar->v2d, 0.0f, 0.0f, &x1, &y1); UI_view2d_view_to_region(&ar->v2d, 1.0f, 1.0f, &x2, &y2); - glRectf(x1, y1, x2, y2); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 20); + immRectf(pos, x1, y1, x2, y2); + immUnbindProgram(); /* gridsize adapted to zoom level */ gridsize = 0.5f * (zoomx + zoomy); @@ -2374,33 +2487,52 @@ void ED_region_grid_draw(ARegion *ar, float zoomx, float zoomy) } } - /* the fine resolution level */ blendfac = 0.25f * gridsize - floorf(0.25f * gridsize); CLAMP(blendfac, 0.0f, 1.0f); - UI_ThemeColorShade(TH_BACK, (int)(20.0f * (1.0f - blendfac))); - fac = 0.0f; - glBegin(GL_LINES); - while (fac < 1.0f) { - glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2); - fac += gridstep; - } + int count_fine = 1.0f / gridstep; + int count_large = 1.0f / (4.0f * gridstep); + + if (count_fine > 0) { + GWN_vertformat_clear(format); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GWN_PRIM_LINES, 4 * count_fine + 4 * count_large); + + float theme_color[3]; + UI_GetThemeColorShade3fv(TH_BACK, (int)(20.0f * (1.0f - blendfac)), theme_color); + immAttrib3fv(color, theme_color); + fac = 0.0f; + + /* the fine resolution level */ + for (int i = 0; i < count_fine; i++) { + immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); + fac += gridstep; + } - /* the large resolution level */ - UI_ThemeColor(TH_BACK); + if (count_large > 0) { + UI_GetThemeColor3fv(TH_BACK, theme_color); + immAttrib3fv(color, theme_color); + fac = 0.0f; + + /* the large resolution level */ + for (int i = 0; i < count_large; i++) { + immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1); + immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y2); + fac += 4.0f * gridstep; + } + } - fac = 0.0f; - while (fac < 1.0f) { - glVertex2f(x1, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x2, y1 * (1.0f - fac) + y2 * fac); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y1); - glVertex2f(x1 * (1.0f - fac) + x2 * fac, y2); - fac += 4.0f * gridstep; + immEnd(); + immUnbindProgram(); } - glEnd(); } /* If the area has overlapping regions, it returns visible rect for Region *ar */ @@ -2437,8 +2569,11 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect) void ED_region_cache_draw_background(const ARegion *ar) { - glColor4ub(128, 128, 255, 64); - glRecti(0, 0, ar->winx, 8 * UI_DPI_FAC); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ub(128, 128, 255, 64); + immRecti(pos, 0, 0, ar->winx, 8 * UI_DPI_FAC); + immUnbindProgram(); } void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y) @@ -2454,9 +2589,13 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f BLF_width_and_height(fontid, numstr, sizeof(numstr), &font_dims[0], &font_dims[1]); - glRecti(x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f); + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColor(TH_CFRAME); + immRecti(pos, x, y, x + font_dims[0] + 6.0f, y + font_dims[1] + 4.0f); + immUnbindProgram(); - UI_ThemeColor(TH_TEXT); + UI_FontThemeColor(fontid, TH_TEXT); BLF_position(fontid, x + 2.0f, y + 2.0f, 0.0f); BLF_draw(fontid, numstr, sizeof(numstr)); } @@ -2464,17 +2603,40 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra) { if (num_segments) { - int a; + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4ub(128, 128, 255, 128); - glColor4ub(128, 128, 255, 128); + for (int a = 0; a < num_segments; a++) { + float x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx; + float x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx; - for (a = 0; a < num_segments; a++) { - float x1, x2; + immRecti(pos, x1, 0, x2, 8 * UI_DPI_FAC); + /* TODO(merwin): use primitive restart to draw multiple rects more efficiently */ + } - x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx; - x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx; + immUnbindProgram(); + } +} - glRecti(x1, 0, x2, 8 * UI_DPI_FAC); - } +/** + * Generate subscriptions for this region. + */ +void ED_region_message_subscribe( + bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + if (ar->manipulator_map != NULL) { + WM_manipulatormap_message_subscribe(C, ar->manipulator_map, ar, mbus); + } + + if (BLI_listbase_is_empty(&ar->uiblocks)) { + UI_region_message_subscribe(ar, mbus); + } + + if (ar->type->message_subscribe != NULL) { + ar->type->message_subscribe(C, workspace, scene, screen, sa, ar, mbus); } } diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 216cbe9d7f4..cd53655a0bb 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -49,133 +49,11 @@ #include "IMB_imbuf_types.h" #include "GPU_basic_shader.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" #include "UI_interface.h" -#ifndef GL_CLAMP_TO_EDGE -#define GL_CLAMP_TO_EDGE 0x812F -#endif - -/* UNUSED */ -#if 0 -void fdrawbezier(float vec[4][3]) -{ - float dist; - float curve_res = 24, spline_step = 0.0f; - - dist = 0.5f * fabsf(vec[0][0] - vec[3][0]); - - /* check direction later, for top sockets */ - vec[1][0] = vec[0][0] + dist; - vec[1][1] = vec[0][1]; - - vec[2][0] = vec[3][0] - dist; - vec[2][1] = vec[3][1]; - /* we can reuse the dist variable here to increment the GL curve eval amount */ - dist = 1.0f / curve_res; - - cpack(0x0); - glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, vec[0]); - glBegin(GL_LINE_STRIP); - while (spline_step < 1.000001f) { -#if 0 - if (do_shaded) - UI_ThemeColorBlend(th_col1, th_col2, spline_step); -#endif - glEvalCoord1f(spline_step); - spline_step += dist; - } - glEnd(); -} -#endif - -void fdrawline(float x1, float y1, float x2, float y2) -{ - glBegin(GL_LINES); - glVertex2f(x1, y1); - glVertex2f(x2, y2); - glEnd(); -} - -void fdrawbox(float x1, float y1, float x2, float y2) -{ - glBegin(GL_LINE_LOOP); - - glVertex2f(x1, y1); - glVertex2f(x1, y2); - glVertex2f(x2, y2); - glVertex2f(x2, y1); - - glEnd(); -} - -void fdrawcheckerboard(float x1, float y1, float x2, float y2) -{ - unsigned char col1[4] = {40, 40, 40}, col2[4] = {50, 50, 50}; - - glColor3ubv(col1); - glRectf(x1, y1, x2, y2); - glColor3ubv(col2); - - GPU_basic_shader_bind(GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR); - GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_CHECKER_8PX); - glRectf(x1, y1, x2, y2); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); -} - -void sdrawline(int x1, int y1, int x2, int y2) -{ - glBegin(GL_LINES); - glVertex2i(x1, y1); - glVertex2i(x2, y2); - glEnd(); -} - -/* UNUSED */ -#if 0 -/* - * x1,y2 - * | \ - * | \ - * | \ - * x1,y1-- x2,y1 - */ - -static void sdrawtripoints(int x1, int y1, int x2, int y2) -{ - glVertex2i(x1, y1); - glVertex2i(x1, y2); - glVertex2i(x2, y1); -} - -void sdrawtri(int x1, int y1, int x2, int y2) -{ - glBegin(GL_LINE_STRIP); - sdrawtripoints(x1, y1, x2, y2); - glEnd(); -} - -void sdrawtrifill(int x1, int y1, int x2, int y2) -{ - glBegin(GL_TRIANGLES); - sdrawtripoints(x1, y1, x2, y2); - glEnd(); -} -#endif - -void sdrawbox(int x1, int y1, int x2, int y2) -{ - glBegin(GL_LINE_LOOP); - - glVertex2i(x1, y1); - glVertex2i(x1, y2); - glVertex2i(x2, y2); - glVertex2i(x2, y1); - - glEnd(); -} - - /* ******************************************** */ void setlinestyle(int nr) @@ -204,122 +82,6 @@ void set_inverted_drawing(int enable) GL_TOGGLE(GL_DITHER, !enable); } -/* UNUSED */ -#if 0 -void sdrawXORline(int x0, int y0, int x1, int y1) -{ - if (x0 == x1 && y0 == y1) return; - - set_inverted_drawing(1); - - glBegin(GL_LINES); - glVertex2i(x0, y0); - glVertex2i(x1, y1); - glEnd(); - - set_inverted_drawing(0); -} - -void sdrawXORline4(int nr, int x0, int y0, int x1, int y1) -{ - static int old[4][2][2]; - static char flags[4] = {0, 0, 0, 0}; - - /* with builtin memory, max 4 lines */ - - set_inverted_drawing(1); - - glBegin(GL_LINES); - if (nr == -1) { /* flush */ - for (nr = 0; nr < 4; nr++) { - if (flags[nr]) { - glVertex2iv(old[nr][0]); - glVertex2iv(old[nr][1]); - flags[nr] = 0; - } - } - } - else { - if (nr >= 0 && nr < 4) { - if (flags[nr]) { - glVertex2iv(old[nr][0]); - glVertex2iv(old[nr][1]); - } - - old[nr][0][0] = x0; - old[nr][0][1] = y0; - old[nr][1][0] = x1; - old[nr][1][1] = y1; - - flags[nr] = 1; - } - - glVertex2i(x0, y0); - glVertex2i(x1, y1); - } - glEnd(); - - set_inverted_drawing(0); -} - -void fdrawXORellipse(float xofs, float yofs, float hw, float hh) -{ - if (hw == 0) return; - - set_inverted_drawing(1); - - glPushMatrix(); - glTranslatef(xofs, yofs, 0.0f); - glScalef(1.0f, hh / hw, 1.0f); - glutil_draw_lined_arc(0.0, M_PI * 2.0, hw, 20); - glPopMatrix(); - - set_inverted_drawing(0); -} - -#endif - -void fdrawXORcirc(float xofs, float yofs, float rad) -{ - set_inverted_drawing(1); - - glPushMatrix(); - glTranslatef(xofs, yofs, 0.0); - glutil_draw_lined_arc(0.0, M_PI * 2.0, rad, 20); - glPopMatrix(); - - set_inverted_drawing(0); -} - -void glutil_draw_filled_arc(float start, float angle, float radius, int nsegments) -{ - int i; - - glBegin(GL_TRIANGLE_FAN); - glVertex2f(0.0, 0.0); - for (i = 0; i < nsegments; i++) { - float t = (float) i / (nsegments - 1); - float cur = start + t * angle; - - glVertex2f(cosf(cur) * radius, sinf(cur) * radius); - } - glEnd(); -} - -void glutil_draw_lined_arc(float start, float angle, float radius, int nsegments) -{ - int i; - - glBegin(GL_LINE_STRIP); - for (i = 0; i < nsegments; i++) { - float t = (float) i / (nsegments - 1); - float cur = start + t * angle; - - glVertex2f(cosf(cur) * radius, sinf(cur) * radius); - } - glEnd(); -} - float glaGetOneFloat(int param) { GLfloat v; @@ -375,24 +137,66 @@ static int get_cached_work_texture(int *r_w, int *r_h) return texid; } -void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, +static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state) +{ + Gwn_VertFormat *vert_format = immVertexFormat(); + state->pos = GWN_vertformat_attr_add(vert_format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + state->texco = GWN_vertformat_attr_add(vert_format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); +} + +/* To be used before calling immDrawPixelsTex + * Default shader is GPU_SHADER_2D_IMAGE_COLOR + * You can still set uniforms with : + * GPU_shader_uniform_int(shader, GPU_shader_get_uniform(shader, "name"), 0); + * */ +IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin) +{ + IMMDrawPixelsTexState state; + immDrawPixelsTexSetupAttributes(&state); + + state.shader = GPU_shader_get_builtin_shader(builtin); + + /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */ + immBindBuiltinProgram(builtin); + immUniform1i("image", 0); + state.do_shader_unbind = true; + + return state; +} + +/* Use the currently bound shader. + * + * Use immDrawPixelsTexSetup to bind the shader you + * want before calling immDrawPixelsTex. + * + * If using a special shader double check it uses the same + * attributes "pos" "texCoord" and uniform "image". + * + * If color is NULL then use white by default + * + * Be also aware that this function unbinds the shader when + * it's finished. + * */ +void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, + float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, float scaleX, float scaleY, float clip_min_x, float clip_min_y, - float clip_max_x, float clip_max_y) + float clip_max_x, float clip_max_y, + float xzoom, float yzoom, float color[4]) { unsigned char *uc_rect = (unsigned char *) rect; const float *f_rect = (float *)rect; - float xzoom = glaGetOneFloat(GL_ZOOM_X), yzoom = glaGetOneFloat(GL_ZOOM_Y); int subpart_x, subpart_y, tex_w, tex_h; int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; int texid = get_cached_work_texture(&tex_w, &tex_h); int components; const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y)); + float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + GLint unpack_row_length; + glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpack_row_length); - /* Specify the color outside this function, and tex will modulate it. - * This is useful for changing alpha without using glPixelTransferf() - */ glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w); glBindTexture(GL_TEXTURE_2D, texid); @@ -401,18 +205,12 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter); -#if defined(__APPLE__) && 0 - /* [merwin] disable this workaround and see if anyone is affected. If not scrap it! Also at end of this function */ - /* workaround for os x 10.5/10.6 driver bug: http://lists.apple.com/archives/Mac-opengl/2008/Jul/msg00117.html */ - glPixelZoom(1.0f, 1.0f); -#endif - /* setup seamless 2=on, 0=off */ seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0; - + offset_x = tex_w - seamless; offset_y = tex_h - seamless; - + nsubparts_x = (img_w + (offset_x - 1)) / (offset_x); nsubparts_y = (img_h + (offset_y - 1)) / (offset_y); @@ -420,7 +218,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, components = 4; else if (format == GL_RGB) components = 3; - else if (ELEM(format, GL_LUMINANCE, GL_ALPHA)) + else if (format == GL_RED) components = 1; else { BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled"); @@ -436,6 +234,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, * it's possible to use GL_RGBA16F_ARB */ + /* TODO viewport : remove extension */ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL); } else { @@ -443,6 +242,16 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL); } + unsigned int pos = state->pos, texco = state->texco; + + /* optional */ + /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since + * it does not need color. + */ + if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) { + immUniformColor4fv((color) ? color : white); + } + for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) { for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) { int remainder_x = img_w - subpart_x * offset_x; @@ -474,7 +283,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, if (type == GL_FLOAT) { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]); - + /* add an extra border of pixels so linear looks ok at edges of full image */ if (subpart_w < tex_w) glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_FLOAT, &f_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); @@ -485,7 +294,7 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, } else { glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, subpart_w, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + subpart_x * offset_x * components]); - + if (subpart_w < tex_w) glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, 0, 1, subpart_h, format, GL_UNSIGNED_BYTE, &uc_rect[((size_t)subpart_y) * offset_y * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); if (subpart_h < tex_h) @@ -494,325 +303,55 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h, glTexSubImage2D(GL_TEXTURE_2D, 0, subpart_w, subpart_h, 1, 1, format, GL_UNSIGNED_BYTE, &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components + (subpart_x * offset_x + subpart_w - 1) * components]); } - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); - glBegin(GL_QUADS); - glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h); - glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom); + immBegin(GWN_PRIM_TRI_FAN, 4); + immAttrib2f(texco, (float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h); + immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom); - glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h); - glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom); + immAttrib2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h); + immVertex2f(pos, rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)offset_bot * yzoom); - glTexCoord2f((float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h); - glVertex2f(rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); + immAttrib2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(subpart_h - offset_top) / tex_h); + immVertex2f(pos, rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); - glTexCoord2f((float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h); - glVertex2f(rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); - glEnd(); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + immAttrib2f(texco, (float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h); + immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY); + immEnd(); } } + if (state->do_shader_unbind) { + immUnbindProgram(); + } + glBindTexture(GL_TEXTURE_2D, 0); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - -#if defined(__APPLE__) && 0 - /* workaround for os x 10.5/10.6 driver bug (above) */ - glPixelZoom(xzoom, yzoom); -#endif + glPixelStorei(GL_UNPACK_ROW_LENGTH, unpack_row_length); } -void glaDrawPixelsTexScaled(float x, float y, int img_w, int img_h, +void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, + float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, - float scaleX, float scaleY) + float scaleX, float scaleY, float xzoom, float yzoom, float color[4]) { - glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, - scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f); + immDrawPixelsTexScaled_clipping(state, x, y, img_w, img_h, format, type, zoomfilter, rect, + scaleX, scaleY, 0.0f, 0.0f, 0.0f, 0.0f, xzoom, yzoom, color); } -void glaDrawPixelsTex(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) +void immDrawPixelsTex(IMMDrawPixelsTexState *state, + float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, + float xzoom, float yzoom, float color[4]) { - glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, - 0.0f, 0.0f, 0.0f, 0.0f); + immDrawPixelsTexScaled_clipping(state, x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, xzoom, yzoom, color); } -void glaDrawPixelsTex_clipping(float x, float y, int img_w, int img_h, +void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, + float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect, - float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y) -{ - glaDrawPixelsTexScaled_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, - clip_min_x, clip_min_y, clip_max_x, clip_max_y); -} - -void glaDrawPixelsSafe(float x, float y, int img_w, int img_h, int row_w, int format, int type, void *rect) -{ - float xzoom = glaGetOneFloat(GL_ZOOM_X); - float yzoom = glaGetOneFloat(GL_ZOOM_Y); - - /* The pixel space coordinate of the intersection of - * the [zoomed] image with the origin. - */ - float ix = -x / xzoom; - float iy = -y / yzoom; - - /* The maximum pixel amounts the image can be cropped - * at the lower left without exceeding the origin. - */ - int off_x = floor(max_ff(ix, 0.0f)); - int off_y = floor(max_ff(iy, 0.0f)); - - /* The zoomed space coordinate of the raster position - * (starting at the lower left most unclipped pixel). - */ - float rast_x = x + off_x * xzoom; - float rast_y = y + off_y * yzoom; - - GLfloat viewport[4]; - int draw_w, draw_h; - - /* Determine the smallest number of pixels we need to draw - * before the image would go off the upper right corner. - * - * It may seem this is just an optimization but some graphics - * cards (ATI) freak out if there is a large zoom factor and - * a large number of pixels off the screen (probably at some - * level the number of image pixels to draw is getting multiplied - * by the zoom and then clamped). Making sure we draw the - * fewest pixels possible keeps everyone mostly happy (still - * fails if we zoom in on one really huge pixel so that it - * covers the entire screen). - */ - glGetFloatv(GL_VIEWPORT, viewport); - draw_w = min_ii(img_w - off_x, ceil((viewport[2] - rast_x) / xzoom)); - draw_h = min_ii(img_h - off_y, ceil((viewport[3] - rast_y) / yzoom)); - - if (draw_w > 0 && draw_h > 0) { - - int bound_options; - GPU_BASIC_SHADER_DISABLE_AND_STORE(bound_options); - - /* Don't use safe RasterPos (slower) if we can avoid it. */ - if (rast_x >= 0 && rast_y >= 0) { - glRasterPos2f(rast_x, rast_y); - } - else { - glaRasterPosSafe2f(rast_x, rast_y, 0, 0); - } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, row_w); - if (format == GL_LUMINANCE || format == GL_RED) { - if (type == GL_FLOAT) { - const float *f_rect = (float *)rect; - glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x)); - } - else if (type == GL_INT || type == GL_UNSIGNED_INT) { - const int *i_rect = (int *)rect; - glDrawPixels(draw_w, draw_h, format, type, i_rect + (off_y * row_w + off_x)); - } - } - else { /* RGBA */ - if (type == GL_FLOAT) { - const float *f_rect = (float *)rect; - glDrawPixels(draw_w, draw_h, format, type, f_rect + (off_y * row_w + off_x) * 4); - } - else if (type == GL_UNSIGNED_BYTE) { - unsigned char *uc_rect = (unsigned char *) rect; - glDrawPixels(draw_w, draw_h, format, type, uc_rect + (off_y * row_w + off_x) * 4); - } - } - - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - - GPU_BASIC_SHADER_ENABLE_AND_RESTORE(bound_options); - } -} - -/* uses either DrawPixelsSafe or DrawPixelsTex, based on user defined maximum */ -void glaDrawPixelsAuto_clipping(float x, float y, int img_w, int img_h, - int format, int type, int zoomfilter, void *rect, - float clip_min_x, float clip_min_y, - float clip_max_x, float clip_max_y) + float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y, + float xzoom, float yzoom, float color[4]) { - if (U.image_draw_method != IMAGE_DRAW_METHOD_DRAWPIXELS) { - glColor4f(1.0, 1.0, 1.0, 1.0); - glaDrawPixelsTex_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, - clip_min_x, clip_min_y, clip_max_x, clip_max_y); - } - else { - glaDrawPixelsSafe(x, y, img_w, img_h, img_w, format, type, rect); - } -} - -void glaDrawPixelsAuto(float x, float y, int img_w, int img_h, int format, int type, int zoomfilter, void *rect) -{ - glaDrawPixelsAuto_clipping(x, y, img_w, img_h, format, type, zoomfilter, rect, - 0.0f, 0.0f, 0.0f, 0.0f); -} - -/* 2D Drawing Assistance */ - -void glaDefine2DArea(rcti *screen_rect) -{ - const int sc_w = BLI_rcti_size_x(screen_rect) + 1; - const int sc_h = BLI_rcti_size_y(screen_rect) + 1; - - glViewport(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h); - glScissor(screen_rect->xmin, screen_rect->ymin, sc_w, sc_h); - - /* The GLA_PIXEL_OFS magic number is to shift the matrix so that - * both raster and vertex integer coordinates fall at pixel - * centers properly. For a longer discussion see the OpenGL - * Programming Guide, Appendix H, Correctness Tips. - */ - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, sc_w, 0.0, sc_h, -1, 1); - glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); -} - -#if 0 /* UNUSED */ - -struct gla2DDrawInfo { - int orig_vp[4], orig_sc[4]; - float orig_projmat[16], orig_viewmat[16]; - - rcti screen_rect; - rctf world_rect; - - float wo_to_sc[2]; -}; - -void gla2DGetMap(gla2DDrawInfo *di, rctf *rect) -{ - *rect = di->world_rect; -} - -void gla2DSetMap(gla2DDrawInfo *di, rctf *rect) -{ - int sc_w, sc_h; - float wo_w, wo_h; - - di->world_rect = *rect; - - sc_w = BLI_rcti_size_x(&di->screen_rect); - sc_h = BLI_rcti_size_y(&di->screen_rect); - wo_w = BLI_rcti_size_x(&di->world_rect); - wo_h = BLI_rcti_size_y(&di->world_rect); - - di->wo_to_sc[0] = sc_w / wo_w; - di->wo_to_sc[1] = sc_h / wo_h; -} - -/** Save the current OpenGL state and initialize OpenGL for 2D - * rendering. glaEnd2DDraw should be called on the returned structure - * to free it and to return OpenGL to its previous state. The - * scissor rectangle is set to match the viewport. - * - * See glaDefine2DArea for an explanation of why this function uses integers. - * - * \param screen_rect The screen rectangle to be used for 2D drawing. - * \param world_rect The world rectangle that the 2D area represented - * by \a screen_rect is supposed to represent. If NULL it is assumed the - * world has a 1 to 1 mapping to the screen. - */ -gla2DDrawInfo *glaBegin2DDraw(rcti *screen_rect, rctf *world_rect) -{ - gla2DDrawInfo *di = MEM_mallocN(sizeof(*di), "gla2DDrawInfo"); - int sc_w, sc_h; - float wo_w, wo_h; - - glGetIntegerv(GL_VIEWPORT, (GLint *)di->orig_vp); - glGetIntegerv(GL_SCISSOR_BOX, (GLint *)di->orig_sc); - glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat *)di->orig_projmat); - glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *)di->orig_viewmat); - - di->screen_rect = *screen_rect; - if (world_rect) { - di->world_rect = *world_rect; - } - else { - di->world_rect.xmin = di->screen_rect.xmin; - di->world_rect.ymin = di->screen_rect.ymin; - di->world_rect.xmax = di->screen_rect.xmax; - di->world_rect.ymax = di->screen_rect.ymax; - } - - sc_w = BLI_rcti_size_x(&di->screen_rect); - sc_h = BLI_rcti_size_y(&di->screen_rect); - wo_w = BLI_rcti_size_x(&di->world_rect); - wo_h = BLI_rcti_size_y(&di->world_rect); - - di->wo_to_sc[0] = sc_w / wo_w; - di->wo_to_sc[1] = sc_h / wo_h; - - glaDefine2DArea(&di->screen_rect); - - return di; -} - -/** - * Translate the (\a wo_x, \a wo_y) point from world coordinates into screen space. - */ -void gla2DDrawTranslatePt(gla2DDrawInfo *di, float wo_x, float wo_y, int *r_sc_x, int *r_sc_y) -{ - *r_sc_x = (wo_x - di->world_rect.xmin) * di->wo_to_sc[0]; - *r_sc_y = (wo_y - di->world_rect.ymin) * di->wo_to_sc[1]; -} - -/** - * Translate the \a world point from world coordinates into screen space. - */ -void gla2DDrawTranslatePtv(gla2DDrawInfo *di, float world[2], int r_screen[2]) -{ - screen_r[0] = (world[0] - di->world_rect.xmin) * di->wo_to_sc[0]; - screen_r[1] = (world[1] - di->world_rect.ymin) * di->wo_to_sc[1]; -} - -/** - * Restores the previous OpenGL state and frees the auxiliary gla data. - */ -void glaEnd2DDraw(gla2DDrawInfo *di) -{ - glViewport(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]); - glScissor(di->orig_vp[0], di->orig_vp[1], di->orig_vp[2], di->orig_vp[3]); - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(di->orig_projmat); - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(di->orig_viewmat); - - MEM_freeN(di); -} -#endif - - -/* Uses current OpenGL state to get view matrices for gluProject/gluUnProject */ -void bgl_get_mats(bglMats *mats) -{ - const double badvalue = 1.0e-6; - - glGetDoublev(GL_MODELVIEW_MATRIX, mats->modelview); - glGetDoublev(GL_PROJECTION_MATRIX, mats->projection); - glGetIntegerv(GL_VIEWPORT, (GLint *)mats->viewport); - - /* Very strange code here - it seems that certain bad values in the - * modelview matrix can cause gluUnProject to give bad results. */ - if (mats->modelview[0] < badvalue && - mats->modelview[0] > -badvalue) - { - mats->modelview[0] = 0; - } - if (mats->modelview[5] < badvalue && - mats->modelview[5] > -badvalue) - { - mats->modelview[5] = 0; - } - - /* Set up viewport so that gluUnProject will give correct values */ - mats->viewport[0] = 0; - mats->viewport[1] = 0; + immDrawPixelsTexScaled_clipping(state, x, y, img_w, img_h, format, type, zoomfilter, rect, 1.0f, 1.0f, + clip_min_x, clip_min_y, clip_max_x, clip_max_y, xzoom, yzoom, color); } /* *************** glPolygonOffset hack ************* */ @@ -831,8 +370,7 @@ void bglPolygonOffset(float viewdist, float dist) // glPolygonOffset(-1.0, -1.0); /* hack below is to mimic polygon offset */ - glMatrixMode(GL_PROJECTION); - glGetFloatv(GL_PROJECTION_MATRIX, (float *)winmat); + gpuGetProjectionMatrix(winmat); /* dist is from camera to center point */ @@ -863,17 +401,13 @@ void bglPolygonOffset(float viewdist, float dist) winmat[14] -= offs; offset += offs; - - glLoadMatrixf(winmat); - glMatrixMode(GL_MODELVIEW); } else { - glMatrixMode(GL_PROJECTION); winmat[14] += offset; offset = 0.0; - glLoadMatrixf(winmat); - glMatrixMode(GL_MODELVIEW); } + + gpuLoadProjectionMatrix(winmat); } /* **** Color management helper functions for GLSL display/transform ***** */ @@ -883,7 +417,8 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, ColorManagedViewSettings *view_settings, ColorManagedDisplaySettings *display_settings, float clip_min_x, float clip_min_y, - float clip_max_x, float clip_max_y) + float clip_max_x, float clip_max_y, + float zoom_x, float zoom_y) { bool force_fallback = false; bool need_fallback = true; @@ -902,6 +437,11 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, if (force_fallback == false) { int ok; + IMMDrawPixelsTexState state = {0}; + /* We want GLSL state to be fully handled by OCIO. */ + state.do_shader_unbind = false; + immDrawPixelsTexSetupAttributes(&state); + if (ibuf->rect_float) { if (ibuf->float_colorspace) { ok = IMB_colormanagement_setup_glsl_draw_from_space(view_settings, display_settings, @@ -920,8 +460,6 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, } if (ok) { - glColor4f(1.0, 1.0, 1.0, 1.0); - if (ibuf->rect_float) { int format = 0; @@ -933,16 +471,20 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, BLI_assert(!"Incompatible number of channels for GLSL display"); if (format != 0) { - glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, format, GL_FLOAT, + immDrawPixelsTex_clipping(&state, + x, y, ibuf->x, ibuf->y, format, GL_FLOAT, zoomfilter, ibuf->rect_float, - clip_min_x, clip_min_y, clip_max_x, clip_max_y); + clip_min_x, clip_min_y, clip_max_x, clip_max_y, + zoom_x, zoom_y, NULL); } } else if (ibuf->rect) { /* ibuf->rect is always RGBA */ - glaDrawPixelsTex_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, + immDrawPixelsTex_clipping(&state, + x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, zoomfilter, ibuf->rect, - clip_min_x, clip_min_y, clip_max_x, clip_max_y); + clip_min_x, clip_min_y, clip_max_x, clip_max_y, + zoom_x, zoom_y, NULL); } IMB_colormanagement_finish_glsl_draw(); @@ -959,9 +501,12 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, display_buffer = IMB_display_buffer_acquire(ibuf, view_settings, display_settings, &cache_handle); if (display_buffer) { - glaDrawPixelsAuto_clipping(x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, - zoomfilter, display_buffer, - clip_min_x, clip_min_y, clip_max_x, clip_max_y); + IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); + immDrawPixelsTex_clipping(&state, + x, y, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, + zoomfilter, display_buffer, + clip_min_x, clip_min_y, clip_max_x, clip_max_y, + zoom_x, zoom_y, NULL); } IMB_display_buffer_release(cache_handle); @@ -970,10 +515,11 @@ void glaDrawImBuf_glsl_clipping(ImBuf *ibuf, float x, float y, int zoomfilter, void glaDrawImBuf_glsl(ImBuf *ibuf, float x, float y, int zoomfilter, ColorManagedViewSettings *view_settings, - ColorManagedDisplaySettings *display_settings) + ColorManagedDisplaySettings *display_settings, + float zoom_x, float zoom_y) { glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings, - 0.0f, 0.0f, 0.0f, 0.0f); + 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y); } void glaDrawImBuf_glsl_ctx_clipping(const bContext *C, @@ -981,7 +527,8 @@ void glaDrawImBuf_glsl_ctx_clipping(const bContext *C, float x, float y, int zoomfilter, float clip_min_x, float clip_min_y, - float clip_max_x, float clip_max_y) + float clip_max_x, float clip_max_y, + float zoom_x, float zoom_y) { ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; @@ -989,22 +536,19 @@ void glaDrawImBuf_glsl_ctx_clipping(const bContext *C, IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings); glaDrawImBuf_glsl_clipping(ibuf, x, y, zoomfilter, view_settings, display_settings, - clip_min_x, clip_min_y, clip_max_x, clip_max_y); -} - -void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter) -{ - glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f); + clip_min_x, clip_min_y, clip_max_x, clip_max_y, + zoom_x, zoom_y); } -void cpack(unsigned int x) +void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter, + float zoom_x, float zoom_y) { - glColor3ub(( (x) & 0xFF), - (((x) >> 8) & 0xFF), - (((x) >> 16) & 0xFF)); + glaDrawImBuf_glsl_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y); } -void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy) +/* don't move to GPU_immediate_util.h because this uses user-prefs + * and isn't very low level */ +void immDrawBorderCorners(unsigned int pos, const rcti *border, float zoomx, float zoomy) { float delta_x = 4.0f * UI_DPI_FAC / zoomx; float delta_y = 4.0f * UI_DPI_FAC / zoomy; @@ -1013,30 +557,30 @@ void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy) delta_y = min_ff(delta_y, border->ymax - border->ymin); /* left bottom corner */ - glBegin(GL_LINE_STRIP); - glVertex2f(border->xmin, border->ymin + delta_y); - glVertex2f(border->xmin, border->ymin); - glVertex2f(border->xmin + delta_x, border->ymin); - glEnd(); + immBegin(GWN_PRIM_LINE_STRIP, 3); + immVertex2f(pos, border->xmin, border->ymin + delta_y); + immVertex2f(pos, border->xmin, border->ymin); + immVertex2f(pos, border->xmin + delta_x, border->ymin); + immEnd(); /* left top corner */ - glBegin(GL_LINE_STRIP); - glVertex2f(border->xmin, border->ymax - delta_y); - glVertex2f(border->xmin, border->ymax); - glVertex2f(border->xmin + delta_x, border->ymax); - glEnd(); + immBegin(GWN_PRIM_LINE_STRIP, 3); + immVertex2f(pos, border->xmin, border->ymax - delta_y); + immVertex2f(pos, border->xmin, border->ymax); + immVertex2f(pos, border->xmin + delta_x, border->ymax); + immEnd(); /* right bottom corner */ - glBegin(GL_LINE_STRIP); - glVertex2f(border->xmax - delta_x, border->ymin); - glVertex2f(border->xmax, border->ymin); - glVertex2f(border->xmax, border->ymin + delta_y); - glEnd(); + immBegin(GWN_PRIM_LINE_STRIP, 3); + immVertex2f(pos, border->xmax - delta_x, border->ymin); + immVertex2f(pos, border->xmax, border->ymin); + immVertex2f(pos, border->xmax, border->ymin + delta_y); + immEnd(); /* right top corner */ - glBegin(GL_LINE_STRIP); - glVertex2f(border->xmax - delta_x, border->ymax); - glVertex2f(border->xmax, border->ymax); - glVertex2f(border->xmax, border->ymax - delta_y); - glEnd(); + immBegin(GWN_PRIM_LINE_STRIP, 3); + immVertex2f(pos, border->xmax - delta_x, border->ymax); + immVertex2f(pos, border->xmax, border->ymax); + immVertex2f(pos, border->xmax, border->ymax - delta_y); + immEnd(); } diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 1190423e2f1..5f8520a92f8 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -38,6 +38,7 @@ #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" #include "BLI_utildefines.h" @@ -47,8 +48,12 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_gpencil.h" +#include "BKE_layer.h" #include "BKE_screen.h" #include "BKE_sequencer.h" +#include "BKE_workspace.h" + +#include "DEG_depsgraph.h" #include "RNA_access.h" @@ -61,20 +66,8 @@ #include "screen_intern.h" -static unsigned int context_layers(bScreen *sc, Scene *scene, ScrArea *sa_ctx) -{ - /* needed for 'USE_ALLSELECT' define, otherwise we end up editing off-screen layers. */ - if (sc && sa_ctx && (sa_ctx->spacetype == SPACE_BUTS)) { - const unsigned int lay = BKE_screen_view3d_layer_all(sc); - if (lay) { - return lay; - } - } - return scene->lay; -} - const char *screen_context_dir[] = { - "scene", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", + "scene", "view_layer", "visible_objects", "visible_bases", "selectable_objects", "selectable_bases", "selected_objects", "selected_bases", "editable_objects", "editable_bases", "selected_editable_objects", "selected_editable_bases", @@ -93,20 +86,13 @@ const char *screen_context_dir[] = { int ed_screen_context(const bContext *C, const char *member, bContextDataResult *result) { + wmWindow *win = CTX_wm_window(C); bScreen *sc = CTX_wm_screen(C); ScrArea *sa = CTX_wm_area(C); - Scene *scene = sc->scene; - Base *base; - -#if 0 /* Using the context breaks adding objects in the UI. Need to find out why - campbell */ - Object *obact = CTX_data_active_object(C); - Object *obedit = CTX_data_edit_object(C); - base = CTX_data_active_base(C); -#else - Object *obedit = scene->obedit; - Object *obact = OBACT; - base = BASACT; -#endif + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace); + Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL; if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); @@ -116,84 +102,100 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult CTX_data_id_pointer_set(result, &scene->id); return 1; } - else if (CTX_data_equals(member, "visible_objects") || CTX_data_equals(member, "visible_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool visible_objects = CTX_data_equals(member, "visible_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) { - if (visible_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + else if (CTX_data_equals(member, "visible_objects")) { + FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, ob) + { + CTX_data_id_list_add(result, &ob->id); + } + FOREACH_VISIBLE_BASE_END + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selectable_objects")) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (((base->flag & BASE_VISIBLED) != 0) && ((base->flag & BASE_SELECTABLED) != 0)) { + CTX_data_id_list_add(result, &base->object->id); } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "selectable_objects") || CTX_data_equals(member, "selectable_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool selectable_objects = CTX_data_equals(member, "selectable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if (base->lay & lay) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0 && (base->object->restrictflag & OB_RESTRICT_SELECT) == 0) { - if (selectable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } + else if (CTX_data_equals(member, "selected_objects")) { + FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob) + { + CTX_data_id_list_add(result, &ob->id); + } + FOREACH_SELECTED_OBJECT_END + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selected_editable_objects")) { + FOREACH_SELECTED_OBJECT_BEGIN(view_layer, ob) + { + if (0 == BKE_object_is_libdata(ob)) { + CTX_data_id_list_add(result, &ob->id); } } + FOREACH_SELECTED_OBJECT_END CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "selected_objects") || CTX_data_equals(member, "selected_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool selected_objects = CTX_data_equals(member, "selected_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if (selected_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + else if (CTX_data_equals(member, "editable_objects")) { + /* Visible + Editable, but not necessarily selected */ + FOREACH_VISIBLE_OBJECT_BEGIN(view_layer, ob) + { + if (0 == BKE_object_is_libdata(ob)) { + CTX_data_id_list_add(result, &ob->id); } } + FOREACH_VISIBLE_OBJECT_END CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "selected_editable_objects") || CTX_data_equals(member, "selected_editable_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool selected_editable_objects = CTX_data_equals(member, "selected_editable_objects"); - - for (base = scene->base.first; base; base = base->next) { - if ((base->flag & SELECT) && (base->lay & lay)) { - if ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) { - if (0 == BKE_object_is_libdata(base->object)) { - if (selected_editable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); - } + else if ( CTX_data_equals(member, "visible_bases")) { + FOREACH_VISIBLE_BASE_BEGIN(view_layer, base) + { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + } + FOREACH_VISIBLE_BASE_END + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selectable_bases")) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTABLED) != 0) { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selected_bases")) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + } + } + CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); + return 1; + } + else if (CTX_data_equals(member, "selected_editable_bases")) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_SELECTED) != 0) { + if (0 == BKE_object_is_libdata(base->object)) { + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); } } } CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); return 1; } - else if (CTX_data_equals(member, "editable_objects") || CTX_data_equals(member, "editable_bases")) { - const unsigned int lay = context_layers(sc, scene, sa); - const bool editable_objects = CTX_data_equals(member, "editable_objects"); - + else if (CTX_data_equals(member, "editable_bases")) { /* Visible + Editable, but not necessarily selected */ - for (base = scene->base.first; base; base = base->next) { - if (((base->object->restrictflag & OB_RESTRICT_VIEW) == 0) && (base->lay & lay)) { + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if ((base->flag & BASE_VISIBLED) != 0) { if (0 == BKE_object_is_libdata(base->object)) { - if (editable_objects) - CTX_data_id_list_add(result, &base->object->id); - else - CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); + CTX_data_list_add(result, &scene->id, &RNA_ObjectBase, base); } } } @@ -201,6 +203,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult return 1; } else if (CTX_data_equals(member, "visible_bones") || CTX_data_equals(member, "editable_bones")) { + Object *obedit = BKE_workspace_edit_object(workspace, scene); bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL; EditBone *ebone, *flipbone = NULL; const bool editable_bones = CTX_data_equals(member, "editable_bones"); @@ -243,6 +246,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } } else if (CTX_data_equals(member, "selected_bones") || CTX_data_equals(member, "selected_editable_bones")) { + Object *obedit = BKE_workspace_edit_object(workspace, scene); bArmature *arm = (obedit && obedit->type == OB_ARMATURE) ? obedit->data : NULL; EditBone *ebone, *flipbone = NULL; const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones"); @@ -345,8 +349,8 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } } else if (CTX_data_equals(member, "active_base")) { - if (base) - CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, base); + if (view_layer->basact) + CTX_data_pointer_set(result, &scene->id, &RNA_ObjectBase, view_layer->basact); return 1; } @@ -364,37 +368,38 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult } else if (CTX_data_equals(member, "edit_object")) { /* convenience for now, 1 object per scene in editmode */ + Object *obedit = BKE_workspace_edit_object(workspace, scene); if (obedit) CTX_data_id_pointer_set(result, &obedit->id); return 1; } else if (CTX_data_equals(member, "sculpt_object")) { - if (obact && (obact->mode & OB_MODE_SCULPT)) + if (obact && (workspace->object_mode & OB_MODE_SCULPT)) { CTX_data_id_pointer_set(result, &obact->id); - + } return 1; } else if (CTX_data_equals(member, "vertex_paint_object")) { - if (obact && (obact->mode & OB_MODE_VERTEX_PAINT)) + if (obact && (workspace->object_mode & OB_MODE_VERTEX_PAINT)) CTX_data_id_pointer_set(result, &obact->id); return 1; } else if (CTX_data_equals(member, "weight_paint_object")) { - if (obact && (obact->mode & OB_MODE_WEIGHT_PAINT)) + if (obact && (workspace->object_mode & OB_MODE_WEIGHT_PAINT)) CTX_data_id_pointer_set(result, &obact->id); return 1; } else if (CTX_data_equals(member, "image_paint_object")) { - if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) + if (obact && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) CTX_data_id_pointer_set(result, &obact->id); return 1; } else if (CTX_data_equals(member, "particle_edit_object")) { - if (obact && (obact->mode & OB_MODE_PARTICLE_EDIT)) + if (obact && (workspace->object_mode & OB_MODE_PARTICLE_EDIT)) CTX_data_id_pointer_set(result, &obact->id); return 1; diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index e67ae4e321c..3ffb125cdde 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -22,18 +22,21 @@ * \ingroup edscr */ -#include "BIF_gl.h" +#include "ED_screen.h" -#include "WM_api.h" +#include "GPU_framebuffer.h" +#include "GPU_immediate.h" +#include "GPU_matrix.h" -#include "ED_screen.h" +#include "WM_api.h" +#include "WM_types.h" #include "screen_intern.h" /** * Draw horizontal shape visualizing future joining (left as well right direction of future joining). */ -static void draw_horizontal_join_shape(ScrArea *sa, char dir) +static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos) { vec2f points[10]; short i; @@ -90,24 +93,31 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir) } } - glBegin(GL_POLYGON); - for (i = 0; i < 5; i++) - glVertex2f(points[i].x, points[i].y); - glEnd(); - glBegin(GL_POLYGON); - for (i = 4; i < 8; i++) - glVertex2f(points[i].x, points[i].y); - glVertex2f(points[0].x, points[0].y); - glEnd(); - - glRectf(points[2].x, points[2].y, points[8].x, points[8].y); - glRectf(points[6].x, points[6].y, points[9].x, points[9].y); + immBegin(GWN_PRIM_TRI_FAN, 5); + + for (i = 0; i < 5; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immEnd(); + + immBegin(GWN_PRIM_TRI_FAN, 5); + + for (i = 4; i < 8; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immVertex2f(pos, points[0].x, points[0].y); + immEnd(); + + immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y); + immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y); } /** * Draw vertical shape visualizing future joining (up/down direction). */ -static void draw_vertical_join_shape(ScrArea *sa, char dir) +static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos) { vec2f points[10]; short i; @@ -144,7 +154,7 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir) points[6].x = sa->v4->vec.x; points[6].y = sa->v4->vec.y + h; - + points[7].x = sa->v3->vec.x; points[7].y = sa->v3->vec.y; @@ -164,93 +174,117 @@ static void draw_vertical_join_shape(ScrArea *sa, char dir) } } - glBegin(GL_POLYGON); - for (i = 0; i < 5; i++) - glVertex2f(points[i].x, points[i].y); - glEnd(); - glBegin(GL_POLYGON); - for (i = 4; i < 8; i++) - glVertex2f(points[i].x, points[i].y); - glVertex2f(points[0].x, points[0].y); - glEnd(); - - glRectf(points[2].x, points[2].y, points[8].x, points[8].y); - glRectf(points[6].x, points[6].y, points[9].x, points[9].y); + immBegin(GWN_PRIM_TRI_FAN, 5); + + for (i = 0; i < 5; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immEnd(); + + immBegin(GWN_PRIM_TRI_FAN, 5); + + for (i = 4; i < 8; i++) { + immVertex2f(pos, points[i].x, points[i].y); + } + + immVertex2f(pos, points[0].x, points[0].y); + immEnd(); + + immRectf(pos, points[2].x, points[2].y, points[8].x, points[8].y); + immRectf(pos, points[6].x, points[6].y, points[9].x, points[9].y); } /** * Draw join shape due to direction of joining. */ -static void draw_join_shape(ScrArea *sa, char dir) +static void draw_join_shape(ScrArea *sa, char dir, unsigned int pos) { if (dir == 'u' || dir == 'd') { - draw_vertical_join_shape(sa, dir); + draw_vertical_join_shape(sa, dir, pos); } else { - draw_horizontal_join_shape(sa, dir); + draw_horizontal_join_shape(sa, dir, pos); } } /** * Draw screen area darker with arrow (visualization of future joining). */ -static void scrarea_draw_shape_dark(ScrArea *sa, char dir) +static void scrarea_draw_shape_dark(ScrArea *sa, char dir, unsigned int pos) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glColor4ub(0, 0, 0, 50); - draw_join_shape(sa, dir); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + immUniformColor4ub(0, 0, 0, 50); + + draw_join_shape(sa, dir, pos); } /** * Draw screen area ligher with arrow shape ("eraser" of previous dark shape). */ -static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir)) +static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir), unsigned int pos) { glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA); /* value 181 was hardly computed: 181~105 */ - glColor4ub(255, 255, 255, 50); + immUniformColor4ub(255, 255, 255, 50); /* draw_join_shape(sa, dir); */ - glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y); + + immRectf(pos, sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y); } -static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2) +static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, unsigned int pos) { + int count = 0; + + if (x2 < sizex - 1) count += 2; + if (x1 > 0) count += 2; + if (y2 < sizey - 1) count += 2; + if (y1 > 0) count += 2; + + if (count == 0) { + return; + } + + immBegin(GWN_PRIM_LINES, count); + /* right border area */ if (x2 < sizex - 1) { - glVertex2s(x2, y1); - glVertex2s(x2, y2); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); } /* left border area */ if (x1 > 0) { /* otherwise it draws the emboss of window over */ - glVertex2s(x1, y1); - glVertex2s(x1, y2); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x1, y2); } /* top border area */ if (y2 < sizey - 1) { - glVertex2s(x1, y2); - glVertex2s(x2, y2); + immVertex2f(pos, x1, y2); + immVertex2f(pos, x2, y2); } /* bottom border area */ if (y1 > 0) { - glVertex2s(x1, y1); - glVertex2s(x2, y1); + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); } + + immEnd(); } /** * \brief Screen edges drawing. */ -static void drawscredge_area(ScrArea *sa, int sizex, int sizey) +static void drawscredge_area(ScrArea *sa, int sizex, int sizey, unsigned int pos) { short x1 = sa->v1->vec.x; short y1 = sa->v1->vec.y; short x2 = sa->v3->vec.x; short y2 = sa->v3->vec.y; - drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2); + drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, pos); } /** @@ -258,33 +292,38 @@ static void drawscredge_area(ScrArea *sa, int sizex, int sizey) */ void ED_screen_draw_edges(wmWindow *win) { + bScreen *screen = WM_window_get_active_screen(win); const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); ScrArea *sa; - wmSubWindowSet(win, win->screen->mainwin); + wmWindowViewport(win); + + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* Note: first loop only draws if U.pixelsize > 1, skip otherwise */ if (U.pixelsize > 1.0f) { /* FIXME: doesn't our glLineWidth already scale by U.pixelsize? */ glLineWidth((2.0f * U.pixelsize) - 1); - glColor3ub(0x50, 0x50, 0x50); - glBegin(GL_LINES); - for (sa = win->screen->areabase.first; sa; sa = sa->next) - drawscredge_area(sa, winsize_x, winsize_y); - glEnd(); + immUniformColor3ub(0x50, 0x50, 0x50); + + for (sa = screen->areabase.first; sa; sa = sa->next) { + drawscredge_area(sa, winsize_x, winsize_y, pos); + } } glLineWidth(1); - glColor3ub(0, 0, 0); - glBegin(GL_LINES); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { - drawscredge_area(sa, winsize_x, winsize_y); + immUniformColor3ub(0, 0, 0); + + for (sa = screen->areabase.first; sa; sa = sa->next) { + drawscredge_area(sa, winsize_x, winsize_y, pos); } - glEnd(); - win->screen->do_draw = false; + immUnbindProgram(); + + screen->do_draw = false; } /** @@ -295,6 +334,9 @@ void ED_screen_draw_edges(wmWindow *win) */ void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2) { + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + glLineWidth(1); /* blended join arrow */ @@ -319,37 +361,155 @@ void ED_screen_draw_join_shape(ScrArea *sa1, ScrArea *sa2) dira = 'd'; break; } + glEnable(GL_BLEND); - scrarea_draw_shape_dark(sa2, dir); - scrarea_draw_shape_light(sa1, dira); + + scrarea_draw_shape_dark(sa2, dir, pos); + scrarea_draw_shape_light(sa1, dira, pos); + glDisable(GL_BLEND); } + + immUnbindProgram(); } void ED_screen_draw_split_preview(ScrArea *sa, const int dir, const float fac) { + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + /* splitpoint */ glEnable(GL_BLEND); - glBegin(GL_LINES); - glColor4ub(255, 255, 255, 100); + immUniformColor4ub(255, 255, 255, 100); + + immBegin(GWN_PRIM_LINES, 2); if (dir == 'h') { const float y = (1 - fac) * sa->totrct.ymin + fac * sa->totrct.ymax; - glVertex2s(sa->totrct.xmin, y); - glVertex2s(sa->totrct.xmax, y); - glColor4ub(0, 0, 0, 100); - glVertex2s(sa->totrct.xmin, y + 1); - glVertex2s(sa->totrct.xmax, y + 1); + + immVertex2f(pos, sa->totrct.xmin, y); + immVertex2f(pos, sa->totrct.xmax, y); + + immEnd(); + + immUniformColor4ub(0, 0, 0, 100); + + immBegin(GWN_PRIM_LINES, 2); + + immVertex2f(pos, sa->totrct.xmin, y + 1); + immVertex2f(pos, sa->totrct.xmax, y + 1); + + immEnd(); } else { + BLI_assert(dir == 'v'); const float x = (1 - fac) * sa->totrct.xmin + fac * sa->totrct.xmax; - glVertex2s(x, sa->totrct.ymin); - glVertex2s(x, sa->totrct.ymax); - glColor4ub(0, 0, 0, 100); - glVertex2s(x + 1, sa->totrct.ymin); - glVertex2s(x + 1, sa->totrct.ymax); + + immVertex2f(pos, x, sa->totrct.ymin); + immVertex2f(pos, x, sa->totrct.ymax); + + immEnd(); + + immUniformColor4ub(0, 0, 0, 100); + + immBegin(GWN_PRIM_LINES, 2); + + immVertex2f(pos, x + 1, sa->totrct.ymin); + immVertex2f(pos, x + 1, sa->totrct.ymax); + + immEnd(); } - glEnd(); + glDisable(GL_BLEND); + + immUnbindProgram(); } + +/* -------------------------------------------------------------------- */ +/* Screen Thumbnail Preview */ + +/** + * Calculates a scale factor to squash the preview for \a screen into a rectangle of given size and aspect. + */ +static void screen_preview_scale_get( + const bScreen *screen, float size_x, float size_y, + const float asp[2], + float r_scale[2]) +{ + float max_x = 0, max_y = 0; + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + max_x = MAX2(max_x, sa->totrct.xmax); + max_y = MAX2(max_y, sa->totrct.ymax); + } + r_scale[0] = (size_x * asp[0]) / max_x; + r_scale[1] = (size_y * asp[1]) / max_y; +} + +static void screen_preview_draw_areas(const bScreen *screen, const float scale[2], const float col[4], + const float ofs_between_areas) +{ + const float ofs_h = ofs_between_areas * 0.5f; + unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformColor4fv(col); + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + rctf rect = { + .xmin = sa->totrct.xmin * scale[0] + ofs_h, + .xmax = sa->totrct.xmax * scale[0] - ofs_h, + .ymin = sa->totrct.ymin * scale[1] + ofs_h, + .ymax = sa->totrct.ymax * scale[1] - ofs_h + }; + + immBegin(GWN_PRIM_TRI_FAN, 4); + immVertex2f(pos, rect.xmin, rect.ymin); + immVertex2f(pos, rect.xmax, rect.ymin); + immVertex2f(pos, rect.xmax, rect.ymax); + immVertex2f(pos, rect.xmin, rect.ymax); + immEnd(); + } + + immUnbindProgram(); +} + +static void screen_preview_draw(const bScreen *screen, int size_x, int size_y) +{ + const float asp[2] = {1.0f, 0.8f}; /* square previews look a bit ugly */ + /* could use theme color (tui.wcol_menu_item.text), but then we'd need to regenerate all previews when changing */ + const float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float scale[2]; + + wmOrtho2(0.0f, size_x, 0.0f, size_y); + /* center */ + gpuPushMatrix(); + gpuLoadIdentity(); + gpuTranslate2f(size_x * (1.0f - asp[0]) * 0.5f, size_y * (1.0f - asp[1]) * 0.5f); + + screen_preview_scale_get(screen, size_x, size_y, asp, scale); + screen_preview_draw_areas(screen, scale, col, 1.5f); + + gpuPopMatrix(); +} + +/** + * Render the preview for a screen layout in \a screen. + */ +void ED_screen_preview_render(const bScreen *screen, int size_x, int size_y, unsigned int *r_rect) +{ + char err_out[256] = "unknown"; + GPUOffScreen *offscreen = GPU_offscreen_create(size_x, size_y, 0, true, false, err_out); + + GPU_offscreen_bind(offscreen, true); + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + screen_preview_draw(screen, size_x, size_y); + + GPU_offscreen_read_pixels(offscreen, GL_UNSIGNED_BYTE, r_rect); + GPU_offscreen_unbind(offscreen, true); + + GPU_offscreen_free(offscreen); +} diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 2cd8ee9223f..08f2242f961 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" #include "DNA_scene_types.h" +#include "DNA_workspace_types.h" #include "DNA_userdef_types.h" #include "BLI_math.h" @@ -41,18 +42,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,8 +66,7 @@ #include "UI_interface.h" -/* XXX actually should be not here... solve later */ -#include "wm_subwindow.h" +#include "WM_message.h" #include "screen_intern.h" /* own module include */ @@ -266,7 +265,7 @@ bool scredge_is_horizontal(ScrEdge *se) } /* need win size to make sure not to include edges along screen edge */ -ScrEdge *screen_find_active_scredge(bScreen *sc, +ScrEdge *screen_find_active_scredge(const bScreen *sc, const int winsize_x, const int winsize_y, const int mx, const int my) { @@ -457,21 +456,17 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge) return newa; } -/* empty screen, with 1 dummy area without spacedata */ -/* uses window size */ -bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name) +/** + * Empty screen, with 1 dummy area without spacedata. Uses window size. + */ +bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y) { - 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(G.main, 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); @@ -489,7 +484,7 @@ bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name) return sc; } -static void screen_copy(bScreen *to, bScreen *from) +void screen_data_copy(bScreen *to, bScreen *from) { ScrVert *s1, *s2; ScrEdge *se; @@ -532,7 +527,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; } @@ -613,6 +617,9 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) screen_delarea(C, scr, sa2); removedouble_scrverts(scr); + /* Update preview thumbnail */ + BKE_icon_changed(scr->id.icon_id); + return 1; } @@ -835,29 +842,23 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y) } + /* ****************** EXPORTED API TO OTHER MODULES *************************** */ -bScreen *ED_screen_duplicate(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! */ - - /* make new empty screen: */ - newsc = ED_screen_add(win, sc->scene, sc->id.name + 2); - /* copy all data */ - screen_copy(newsc, sc); - - return newsc; -} + bScreen *screen = WM_window_get_active_screen(win); -/* 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) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { 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 +870,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; } } @@ -905,49 +907,40 @@ static void screen_refresh_headersizes(void) /* make this screen usable */ /* 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); - - 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_test_scale(screen, winsize_x, winsize_y); - for (sa = win->screen->areabase.first; sa; sa = sa->next) { + for (sa = screen->areabase.first; sa; sa = sa->next) { /* set spacetype and region callbacks, calls init() */ /* sets subwindows for regions, adds handlers */ ED_area_initialize(wm, win, sa); } /* 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 +949,10 @@ void ED_screens_initialize(wmWindowManager *wm) wmWindow *win; for (win = wm->windows.first; win; win = win->next) { - - if (win->screen == NULL) - win->screen = G.main->screen.first; - + if (WM_window_get_active_workspace(win) == NULL) { + WM_window_set_active_workspace(win, G.main->workspaces.first); + } + ED_screen_refresh(wm, win); } } @@ -970,17 +963,17 @@ void ED_screens_initialize(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); + ar->visible = 0; if (ar->headerstr) { MEM_freeN(ar->headerstr); @@ -988,16 +981,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 +1001,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); } @@ -1026,10 +1025,7 @@ 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) ED_region_exit(C, ar); @@ -1040,7 +1036,7 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen) /* 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); } @@ -1056,13 +1052,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) { + const bScreen *screen = WM_window_get_active_screen(win); const int winsize_x = WM_window_pixels_x(win); const int winsize_y = WM_window_pixels_y(win); AZone *az = NULL; ScrArea *sa; - for (sa = win->screen->areabase.first; sa; sa = sa->next) + for (sa = screen->areabase.first; sa; sa = sa->next) if ((az = is_in_area_actionzone(sa, &event->x))) break; @@ -1077,7 +1074,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(screen, winsize_x, winsize_y, event->x, event->y); if (actedge) { if (scredge_is_horizontal(actedge)) @@ -1093,15 +1090,15 @@ 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, const wmEvent *event) { wmWindow *win = CTX_wm_window(C); - - if (win->screen) { - bScreen *scr = win->screen; + bScreen *scr = WM_window_get_active_screen(win); + + if (scr) { ScrArea *sa; 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) @@ -1113,22 +1110,22 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) /* 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; + 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) { bool do_draw = false; for (ar = sa->regionbase.first; ar; ar = ar->next) - if (ar->swinid == oldswin || ar->swinid == scr->subwinactive) + if (ar == old_ar || ar == scr->active_region) do_draw = true; if (do_draw) { @@ -1140,21 +1137,21 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event) } /* cursors, for time being set always on edges, otherwise aregion doesnt switch */ - if (scr->subwinactive == scr->mainwin) { + if (scr->active_region == NULL) { screen_cursor_set(win, event); } 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); + UI_screen_free_active_but(C, scr); } else - region_cursor_set(win, scr->subwinactive, false); + region_cursor_set(win, false); } } } @@ -1173,183 +1170,126 @@ 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; } + +/* -------------------------------------------------------------------- */ +/* 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->full == screen) { + return screen_iter; + } + } + + return screen; +} + /** - * operator call, WM + Window + screen already existed before - * - * \warning Do NOT call in area/region queues! - * \returns success. + * \return the screen to activate. + * \warning The returned screen may not always equal \a screen_new! */ -bool ED_screen_set(bContext *C, bScreen *sc) +bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win) { - Main *bmain = CTX_data_main(C); - wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *win = CTX_wm_window(C); - bScreen *oldscreen = CTX_wm_screen(C); - /* validate screen, it's called with notifier reference */ - if (BLI_findindex(&bmain->screen, sc) == -1) { - return true; + if (BLI_findindex(&bmain->screen, screen_new) == -1) { + return NULL; } - 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; - } - } + 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); - } - } - - 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); + screen_new->animtimer = wt; } - /* 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; - - /* don't allow deleting temp fullscreens for now */ - if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) { - return false; - } + bScreen *screen_old = CTX_wm_screen(C); + bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win); - /* 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 */ + 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); - 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; - } - - 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; @@ -1373,93 +1313,16 @@ 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 | EM_DO_UNDO); - - 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; - } - - } - } - - // 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; + 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); } } } - - 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) @@ -1566,6 +1429,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa) ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state) { wmWindowManager *wm = CTX_wm_manager(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); bScreen *sc, *oldscreen; ARegion *ar; @@ -1587,9 +1451,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; @@ -1628,9 +1493,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. @@ -1640,14 +1505,18 @@ 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; + 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(win, oldscreen->scene, newname); + + layout_new = ED_workspace_layout_add(workspace, win, newname); + + sc = BKE_workspace_layout_screen_get(layout_new); sc->state = state; sc->redraws_flag = oldscreen->redraws_flag; sc->temp = oldscreen->temp; @@ -1702,7 +1571,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s BLI_assert(false); } - ED_screen_set(C, sc); + ED_screen_change(C, sc); } /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */ @@ -1837,14 +1706,9 @@ 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, Scene *scene, ViewLayer *view_layer, struct Depsgraph *depsgraph) { - wmWindowManager *wm = bmain->wm.first; - wmWindow *window; - int layers = 0; - #ifdef DURIAN_CAMERA_SWITCH void *camera = BKE_scene_camera_switch_find(scene); if (camera && scene->camera != camera) { @@ -1852,19 +1716,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(bmain->eval_ctx, depsgraph, bmain, scene, view_layer); /* composite */ if (scene->use_nodes && scene->nodetree) @@ -1885,11 +1745,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) { @@ -1964,3 +1823,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; +} diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index db5259f5865..6d0a9f1e7d0 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -33,6 +33,7 @@ struct bContext; struct bContextDataResult; +struct Main; /* internal exports only */ @@ -43,9 +44,14 @@ struct bContextDataResult; /* area.c */ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free); void ED_area_data_swap(ScrArea *sa1, ScrArea *sa2); -void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade); +void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade); /* screen_edit.c */ +bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y); +void screen_data_copy(bScreen *to, bScreen *from); +void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new); +void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc); +bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, struct Main *bmain, struct bContext *C, wmWindow *win); ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2); ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge); int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2); @@ -57,7 +63,7 @@ void removedouble_scrverts(bScreen *sc); void removedouble_scredges(bScreen *sc); void removenotused_scredges(bScreen *sc); bool scredge_is_horizontal(ScrEdge *se); -ScrEdge *screen_find_active_scredge(bScreen *sc, +ScrEdge *screen_find_active_scredge(const bScreen *sc, const int winsize_x, const int winsize_y, const int mx, const int my); @@ -76,5 +82,8 @@ void SCREEN_OT_screencast(struct wmOperatorType *ot); /* screen_ops.c */ void region_blend_start(struct bContext *C, struct ScrArea *sa, struct ARegion *ar); +/* workspace_layout_edit.c */ +bool workspace_layout_set_poll(const struct WorkSpaceLayout *layout); + #endif /* __SCREEN_INTERN_H__ */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 2e5f93ff521..86a5b800c44 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -48,11 +48,13 @@ #include "DNA_meta_types.h" #include "DNA_mask_types.h" #include "DNA_node_types.h" +#include "DNA_workspace_types.h" #include "DNA_userdef_types.h" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" @@ -61,10 +63,13 @@ #include "BKE_editmesh.h" #include "BKE_sound.h" #include "BKE_mask.h" +#include "BKE_workspace.h" #include "WM_api.h" #include "WM_types.h" +#include "DEG_depsgraph.h" + #include "ED_armature.h" #include "ED_clip.h" #include "ED_image.h" @@ -133,7 +138,7 @@ int ED_operator_screen_mainwinactive(bContext *C) if (CTX_wm_window(C) == NULL) return 0; screen = CTX_wm_screen(C); if (screen == NULL) return 0; - if (screen->subwinactive != screen->mainwin) return 0; + if (screen->active_region != NULL) return 0; return 1; } @@ -147,6 +152,7 @@ int ED_operator_scene_editable(bContext *C) int ED_operator_objectmode(bContext *C) { + const WorkSpace *workspace = CTX_wm_workspace(C); Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); @@ -156,7 +162,7 @@ int ED_operator_objectmode(bContext *C) return 0; /* add a check for ob->mode too? */ - if (obact && (obact->mode != OB_MODE_OBJECT)) + if (obact && (workspace->object_mode != OB_MODE_OBJECT)) return 0; return 1; @@ -298,35 +304,39 @@ int ED_operator_console_active(bContext *C) return ed_spacetype_test(C, SPACE_CONSOLE); } -static int ed_object_hidden(Object *ob) +static int ed_object_hidden(Object *ob, eObjectMode object_mode) { /* if hidden but in edit mode, we still display, can happen with animation */ - return ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT)); + return ((ob->restrictflag & OB_RESTRICT_VIEW) && !(object_mode & OB_MODE_EDIT)); } int ED_operator_object_active(bContext *C) { + const WorkSpace *workspace = CTX_wm_workspace(C); Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !ed_object_hidden(ob)); + return ((ob != NULL) && !ed_object_hidden(ob, workspace->object_mode)); } int ED_operator_object_active_editable(bContext *C) { + const WorkSpace *workspace = CTX_wm_workspace(C); Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob)); + return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob, workspace->object_mode)); } int ED_operator_object_active_editable_mesh(bContext *C) { + const WorkSpace *workspace = CTX_wm_workspace(C); Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && + return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob, workspace->object_mode) && (ob->type == OB_MESH) && !ID_IS_LINKED(ob->data)); } int ED_operator_object_active_editable_font(bContext *C) { + const WorkSpace *workspace = CTX_wm_workspace(C); Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob) && + return ((ob != NULL) && !ID_IS_LINKED(ob) && !ed_object_hidden(ob, workspace->object_mode) && (ob->type == OB_FONT)); } @@ -371,11 +381,14 @@ int ED_operator_posemode_exclusive(bContext *C) { Object *obact = CTX_data_active_object(C); - if (obact && !(obact->mode & OB_MODE_EDIT)) { - Object *obpose; - if ((obpose = BKE_object_pose_armature_get(obact))) { - if (obact == obpose) { - return 1; + if (obact) { + const WorkSpace *workspace = CTX_wm_workspace(C); + if ((workspace->object_mode & OB_MODE_EDIT) == 0) { + Object *obpose; + if ((obpose = BKE_object_pose_armature_get(obact))) { + if (obact == obpose) { + return 1; + } } } } @@ -389,9 +402,15 @@ int ED_operator_posemode_context(bContext *C) { Object *obpose = ED_pose_object_from_context(C); - if (obpose && !(obpose->mode & OB_MODE_EDIT)) { - if (BKE_object_pose_context_check(obpose)) { - return 1; + if (obpose) { + const WorkSpace *workspace = CTX_wm_workspace(C); + /* TODO, should we allow this out of pose mode? */ + if (workspace->object_mode & OB_MODE_POSE) { + // if ((workspace->object_mode & OB_MODE_EDIT) == 0) { + if (BKE_object_pose_context_check(obpose)) { + return 1; + } + // } } } @@ -402,11 +421,17 @@ int ED_operator_posemode(bContext *C) { Object *obact = CTX_data_active_object(C); - if (obact && !(obact->mode & OB_MODE_EDIT)) { - Object *obpose; - if ((obpose = BKE_object_pose_armature_get(obact))) { - if ((obact == obpose) || (obact->mode & OB_MODE_WEIGHT_PAINT)) { - return 1; + + if (obact) { + const WorkSpace *workspace = CTX_wm_workspace(C); + if ((workspace->object_mode & OB_MODE_EDIT) == 0) { + Object *obpose; + if ((obpose = BKE_object_pose_armature_get(obact))) { + if (((workspace->object_mode & OB_MODE_POSE) && (obact == obpose)) || + (workspace->object_mode & OB_MODE_WEIGHT_PAINT)) + { + return 1; + } } } } @@ -542,9 +567,10 @@ int ED_operator_mask(bContext *C) } case SPACE_IMAGE: { + WorkSpace *workspace = CTX_wm_workspace(C); SpaceImage *sima = sa->spacedata.first; - Scene *scene = CTX_data_scene(C); - return ED_space_image_check_show_maskedit(scene, sima); + ViewLayer *view_layer = CTX_data_view_layer(C); + return ED_space_image_check_show_maskedit(sima, workspace, view_layer); } } } @@ -552,6 +578,12 @@ int ED_operator_mask(bContext *C) return false; } +int ED_operator_camera(bContext *C) +{ + struct Camera *cam = CTX_data_pointer_get_type(C, "camera", &RNA_Camera).data; + return (cam != NULL); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -998,13 +1030,17 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot) /* operator callback */ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - wmWindow *newwin, *win; - bScreen *newsc, *sc; + wmWindow *newwin, *win = CTX_wm_window(C); + Scene *scene; + WorkSpace *workspace = WM_window_get_active_workspace(win); + WorkSpaceLayout *layout_old = WM_window_get_active_layout(win); + WorkSpaceLayout *layout_new; + bScreen *newsc; ScrArea *sa; rcti rect; win = CTX_wm_window(C); - sc = CTX_wm_screen(C); + scene = CTX_data_scene(C); sa = CTX_wm_area(C); /* XXX hrmf! */ @@ -1030,11 +1066,15 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event) } *newwin->stereo3d_format = *win->stereo3d_format; - + + newwin->scene = scene; + + WM_window_set_active_workspace(newwin, workspace); /* allocs new screen and adds to newly created window, using window size */ - newsc = ED_screen_add(newwin, CTX_data_scene(C), sc->id.name + 2); - newwin->screen = newsc; - + layout_new = ED_workspace_layout_add(workspace, newwin, BKE_workspace_layout_name_get(layout_old)); + newsc = BKE_workspace_layout_screen_get(layout_new); + WM_window_set_active_layout(newwin, workspace, layout_new); + /* copy area to new screen */ ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true); @@ -1288,6 +1328,8 @@ static void area_move_apply_do( } } WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */ + /* Update preview thumbnail */ + BKE_icon_changed(sc->id.icon_id); } } @@ -1583,7 +1625,9 @@ static int area_split_apply(bContext *C, wmOperator *op) ED_area_tag_redraw(sd->narea); WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); - + /* Update preview thumbnail */ + BKE_icon_changed(sc->id.icon_id); + return 1; } @@ -1852,7 +1896,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_area_tag_redraw(sd->sarea); } - CTX_wm_window(C)->screen->do_draw = true; + CTX_wm_screen(C)->do_draw = true; } float fac = (float)(sd->delta + sd->origval - sd->origmin) / sd->origsize; @@ -2175,12 +2219,11 @@ static void areas_do_frame_follow(bContext *C, bool middle) bScreen *scr = CTX_wm_screen(C); Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); - wmWindow *window; - for (window = wm->windows.first; window; window = window->next) { - ScrArea *sa; - for (sa = window->screen->areabase.first; sa; sa = sa->next) { - ARegion *ar; - for (ar = sa->regionbase.first; ar; ar = ar->next) { + for (wmWindow *window = wm->windows.first; window; window = window->next) { + const bScreen *screen = WM_window_get_active_screen(window); + + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { /* do follow here if editor type supports it */ if ((scr->redraws_flag & TIME_FOLLOW)) { if ((ar->regiontype == RGN_TYPE_WINDOW && @@ -2495,64 +2538,16 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot) /** \name Set Screen Operator * \{ */ -static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev) -{ - return ((screen->winid == 0) && - /* in typical usage these should have a nonzero winid - * (all temp screens should be used, or closed & freed). */ - (screen->temp == false) && - (screen->state == SCREENNORMAL) && - (screen != screen_prev) && - (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT))); -} - /* function to be called outside UI context, or for redo */ static int screen_set_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - bScreen *screen = CTX_wm_screen(C); - bScreen *screen_prev = screen; - - ScrArea *sa = CTX_wm_area(C); - int tot = BLI_listbase_count(&bmain->screen); + WorkSpace *workspace = CTX_wm_workspace(C); int delta = RNA_int_get(op->ptr, "delta"); - - /* temp screens are for userpref or render display */ - if (screen->temp || (sa && sa->full && sa->full->temp)) { - return OPERATOR_CANCELLED; - } - - if (delta == 1) { - while (tot--) { - screen = screen->id.next; - if (screen == NULL) screen = bmain->screen.first; - if (screen_set_is_ok(screen, screen_prev)) { - break; - } - } - } - else if (delta == -1) { - while (tot--) { - screen = screen->id.prev; - if (screen == NULL) screen = bmain->screen.last; - if (screen_set_is_ok(screen, screen_prev)) { - break; - } - } - } - else { - screen = NULL; - } - - if (screen && screen_prev != screen) { - /* return to previous state before switching screens */ - if (sa && sa->full) { - ED_screen_full_restore(C, sa); /* may free 'screen_prev' */ - } - - ED_screen_set(C, screen); + + if (ED_workspace_layout_cycle(workspace, delta, C)) { return OPERATOR_FINISHED; } + return OPERATOR_CANCELLED; } @@ -3396,7 +3391,7 @@ static int header_toggle_menus_exec(bContext *C, wmOperator *UNUSED(op)) sa->flag = sa->flag ^ HEADER_NO_PULLDOWN; ED_area_tag_redraw(sa); - WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); return OPERATOR_FINISHED; } @@ -3589,6 +3584,8 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv if (screen->animtimer && screen->animtimer == event->customdata) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + struct Depsgraph *depsgraph = CTX_data_depsgraph(C); wmTimer *wt = screen->animtimer; ScreenAnimData *sad = wt->customdata; wmWindowManager *wm = CTX_wm_manager(C); @@ -3699,10 +3696,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } /* since we follow drawflags, we can't send notifier but tag regions ourselves */ - ED_update_for_newframe(bmain, scene, 1); + ED_update_for_newframe(bmain, scene, view_layer, depsgraph); for (window = wm->windows.first; window; window = window->next) { - for (sa = window->screen->areabase.first; sa; sa = sa->next) { + const bScreen *win_screen = WM_window_get_active_screen(window); + + for (sa = win_screen->areabase.first; sa; sa = sa->next) { ARegion *ar; for (ar = sa->regionbase.first; ar; ar = ar->next) { bool redraw = false; @@ -3782,11 +3781,11 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot) /* find window that owns the animation timer */ bScreen *ED_screen_animation_playing(const wmWindowManager *wm) { - wmWindow *win; + for (wmWindow *win = wm->windows.first; win; win = win->next) { + bScreen *screen = WM_window_get_active_screen(win); - for (win = wm->windows.first; win; win = win->next) { - if (win->screen->animtimer || win->screen->scrubbing) { - return win->screen; + if (screen->animtimer || screen->scrubbing) { + return screen; } } @@ -3795,11 +3794,11 @@ bScreen *ED_screen_animation_playing(const wmWindowManager *wm) bScreen *ED_screen_animation_no_scrub(const wmWindowManager *wm) { - wmWindow *win; + for (wmWindow *win = wm->windows.first; win; win = win->next) { + bScreen *screen = WM_window_get_active_screen(win); - for (win = wm->windows.first; win; win = win->next) { - if (win->screen->animtimer) { - return win->screen; + if (screen->animtimer) { + return screen; } } @@ -4057,11 +4056,13 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) static int screen_new_exec(bContext *C, wmOperator *UNUSED(op)) { wmWindow *win = CTX_wm_window(C); - bScreen *sc = CTX_wm_screen(C); - - sc = ED_screen_duplicate(win, sc); - WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, sc); - + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook); + WorkSpaceLayout *layout_new; + + layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win); + WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new); + return OPERATOR_FINISHED; } @@ -4086,9 +4087,11 @@ static void SCREEN_OT_new(wmOperatorType *ot) static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op)) { bScreen *sc = CTX_wm_screen(C); - - WM_event_add_notifier(C, NC_SCREEN | ND_SCREENDELETE, sc); - + WorkSpace *workspace = CTX_wm_workspace(C); + WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc); + + WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout); + return OPERATOR_FINISHED; } @@ -4106,103 +4109,6 @@ static void SCREEN_OT_delete(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name New Scene Operator - * \{ */ - -static int scene_new_exec(bContext *C, wmOperator *op) -{ - Scene *newscene, *scene = CTX_data_scene(C); - Main *bmain = CTX_data_main(C); - int type = RNA_enum_get(op->ptr, "type"); - - if (type == SCE_COPY_NEW) { - newscene = BKE_scene_add(bmain, DATA_("Scene")); - } - else { /* different kinds of copying */ - newscene = BKE_scene_copy(bmain, scene, type); - - /* these can't be handled in blenkernel currently, so do them here */ - if (type == SCE_COPY_LINK_DATA) { - ED_object_single_users(bmain, newscene, false, true); - } - else if (type == SCE_COPY_FULL) { - ED_editors_flush_edits(C, false); - ED_object_single_users(bmain, newscene, true, true); - } - } - - ED_screen_set_scene(C, CTX_wm_screen(C), newscene); - - WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, newscene); - - return OPERATOR_FINISHED; -} - -static void SCENE_OT_new(wmOperatorType *ot) -{ - static const EnumPropertyItem type_items[] = { - {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"}, - {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"}, - {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"}, - {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"}, - {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"}, - {0, NULL, 0, NULL, NULL}}; - - /* identifiers */ - ot->name = "New Scene"; - ot->description = "Add new scene by type"; - ot->idname = "SCENE_OT_new"; - - /* api callbacks */ - ot->exec = scene_new_exec; - ot->invoke = WM_menu_invoke; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Delete Screen Operator - * \{ */ - -static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Scene *scene = CTX_data_scene(C); - - if (ED_screen_delete_scene(C, scene) == false) { - return OPERATOR_CANCELLED; - } - - if (G.debug & G_DEBUG) - printf("scene delete %p\n", scene); - - WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene); - - return OPERATOR_FINISHED; -} - -static void SCENE_OT_delete(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Delete Scene"; - ot->description = "Delete active scene"; - ot->idname = "SCENE_OT_delete"; - - /* api callbacks */ - ot->exec = scene_delete_exec; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Region Alpha Blending Operator * \{ */ @@ -4480,13 +4386,11 @@ void ED_operatortypes_screen(void) WM_operatortype_append(SCREEN_OT_animation_step); WM_operatortype_append(SCREEN_OT_animation_play); WM_operatortype_append(SCREEN_OT_animation_cancel); - + /* new/delete */ WM_operatortype_append(SCREEN_OT_new); WM_operatortype_append(SCREEN_OT_delete); - WM_operatortype_append(SCENE_OT_new); - WM_operatortype_append(SCENE_OT_delete); - + /* tools shared by more space types */ WM_operatortype_append(ED_OT_undo); WM_operatortype_append(ED_OT_undo_push); diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 2dd7400bc37..69891a727d4 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -54,7 +54,9 @@ #include "BKE_writeavi.h" #include "BIF_gl.h" -#include "BIF_glutil.h" + +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" #include "RNA_access.h" #include "RNA_define.h" @@ -451,25 +453,24 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float /* Helper callback for drawing the cursor itself */ static void screencast_draw_cursor(bContext *UNUSED(C), int x, int y, void *UNUSED(p_ptr)) { - - glPushMatrix(); - - glTranslatef((float)x, (float)y, 0.0f); - - glEnable(GL_LINE_SMOOTH); glEnable(GL_BLEND); - - glColor4ub(0, 0, 0, 32); - glutil_draw_filled_arc(0.0, M_PI * 2.0, 20, 40); - - glColor4ub(255, 255, 255, 128); - glutil_draw_lined_arc(0.0, M_PI * 2.0, 20, 40); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + immUniformColor4ub(0, 0, 0, 32); + imm_draw_circle_fill_2d(pos, (float)x, (float)y, 20, 40); + + immUniformColor4ub(255, 255, 255, 128); + imm_draw_circle_wire_2d(pos, (float)x, (float)y, 20, 40); + + immUnbindProgram(); glDisable(GL_BLEND); glDisable(GL_LINE_SMOOTH); - - glPopMatrix(); } /* Turn brush cursor in 3D view on/off */ diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c new file mode 100644 index 00000000000..2b28f61f901 --- /dev/null +++ b/source/blender/editors/screen/workspace_edit.c @@ -0,0 +1,524 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/screen/workspace_edit.c + * \ingroup edscr + */ + +#include <stdlib.h> +#include <string.h> + +#include "BLI_utildefines.h" +#include "BLI_fileops.h" +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_appdir.h" +#include "BKE_blendfile.h" +#include "BKE_context.h" +#include "BKE_idcode.h" +#include "BKE_main.h" +#include "BKE_layer.h" +#include "BKE_library.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_workspace.h" + +#include "BLO_readfile.h" + +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_workspace_types.h" + +#include "ED_object.h" +#include "ED_screen.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "DEG_depsgraph.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "screen_intern.h" + + +/** \name Workspace API + * + * \brief API for managing workspaces and their data. + * \{ */ + +WorkSpace *ED_workspace_add( + Main *bmain, const char *name, Scene *scene, + ViewLayer *act_view_layer, ViewRender *view_render) +{ + WorkSpace *workspace = BKE_workspace_add(bmain, name); + + BKE_workspace_view_layer_set(workspace, act_view_layer, scene); + BKE_viewrender_copy(&workspace->view_render, view_render); + + return workspace; +} + +static void workspace_change_update_view_layer( + WorkSpace *workspace_new, const WorkSpace *workspace_old, + Scene *scene) +{ + if (!BKE_workspace_view_layer_get(workspace_new, scene)) { + BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old, scene), scene); + } +} + +static void workspace_change_update( + WorkSpace *workspace_new, const WorkSpace *workspace_old, + bContext *C) +{ + /* needs to be done before changing mode! (to ensure right context) */ + workspace_change_update_view_layer(workspace_new, workspace_old, CTX_data_scene(C)); +} + +static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg)) +{ + /* return false to stop the iterator if we've found a layout that can be activated */ + return workspace_layout_set_poll(layout) ? false : true; +} + +static WorkSpaceLayout *workspace_change_get_new_layout( + WorkSpace *workspace_new, wmWindow *win) +{ + /* ED_workspace_duplicate may have stored a layout to activate once the workspace gets activated. */ + WorkSpaceLayout *layout_new; + bScreen *screen_new; + + if (win->workspace_hook->temp_workspace_store) { + layout_new = win->workspace_hook->temp_layout_store; + } + else { + layout_new = BKE_workspace_hook_layout_for_workspace_get(win->workspace_hook, workspace_new); + if (!layout_new) { + layout_new = BKE_workspace_layouts_get(workspace_new)->first; + } + } + screen_new = BKE_workspace_layout_screen_get(layout_new); + + if (screen_new->winid) { + /* screen is already used, try to find a free one */ + WorkSpaceLayout *layout_temp = BKE_workspace_layout_iter_circular( + workspace_new, layout_new, workspace_change_find_new_layout_cb, + NULL, false); + if (!layout_temp) { + /* fallback solution: duplicate layout */ + layout_temp = ED_workspace_layout_duplicate(workspace_new, layout_new, win); + } + layout_new = layout_temp; + } + + return layout_new; +} + +/** + * \brief Change the active workspace. + * + * Operator call, WM + Window + screen already existed before + * Pretty similar to #ED_screen_change since changing workspace also changes screen. + * + * \warning Do NOT call in area/region queues! + * \returns if workspace changing was successful. + */ +bool ED_workspace_change( + WorkSpace *workspace_new, bContext *C, wmWindow *win) +{ + Main *bmain = CTX_data_main(C); + WorkSpace *workspace_old = WM_window_get_active_workspace(win); + WorkSpaceLayout *layout_new = workspace_change_get_new_layout(workspace_new, win); + bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new); + bScreen *screen_old = BKE_workspace_active_screen_get(win->workspace_hook); + + win->workspace_hook->temp_layout_store = NULL; + if (workspace_old == workspace_new) { + /* Could also return true, everything that needs to be done was done (nothing :P), but nothing changed */ + return false; + } + + screen_new = screen_change_prepare(screen_old, screen_new, bmain, C, win); + BLI_assert(BKE_workspace_layout_screen_get(layout_new) == screen_new); + + if (screen_new) { + bool use_object_mode = false; + + /* Store old context for exiting edit-mode. */ + EvaluationContext eval_ctx_old; + CTX_data_eval_ctx(C, &eval_ctx_old); + Scene *scene = WM_window_get_active_scene(win); + ViewLayer *view_layer_old = BKE_workspace_view_layer_get(workspace_old, scene); + Object *obact_old = OBACT(view_layer_old); + + ViewLayer *view_layer_new = BKE_workspace_view_layer_get(workspace_new, scene); + Object *obact_new = OBACT(view_layer_new); + + /* Handle object mode switching */ + if ((workspace_old->object_mode != OB_MODE_OBJECT) || + (workspace_new->object_mode != OB_MODE_OBJECT)) + { + if ((workspace_old->object_mode == workspace_new->object_mode) && + (obact_old == obact_new)) + { + /* pass */ + } + else { + use_object_mode = true; + } + } + + + WM_window_set_active_layout(win, workspace_new, layout_new); + WM_window_set_active_workspace(win, workspace_new); + + /* update screen *after* changing workspace - which also causes the actual screen change */ + screen_change_update(C, win, screen_new); + workspace_change_update(workspace_new, workspace_old, C); + + BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL); + BLI_assert(CTX_wm_workspace(C) == workspace_new); + + WM_toolsystem_unlink(C, workspace_old); + WM_toolsystem_link(C, workspace_new); + + if (use_object_mode) { + /* weak, set it back so it's used when activating again. */ + eObjectMode object_mode = workspace_old->object_mode; + ED_object_mode_generic_exit_or_other_window(&eval_ctx_old, bmain->wm.first, workspace_old, scene, obact_old); + workspace_old->object_mode = object_mode; + ED_workspace_object_mode_sync_from_object(bmain->wm.first, workspace_old, obact_old); + ED_object_mode_generic_enter_or_other_window(C, NULL, workspace_new->object_mode); + } + else { + if (obact_new == NULL) { + workspace_new->object_mode = OB_MODE_OBJECT; + } + } + + return true; + } + + return false; +} + +/** + * Duplicate a workspace including its layouts. Does not activate the workspace, but + * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store) + */ +WorkSpace *ED_workspace_duplicate( + WorkSpace *workspace_old, Main *bmain, wmWindow *win) +{ + WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook); + ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old); + Scene *scene = WM_window_get_active_scene(win); + WorkSpace *workspace_new = ED_workspace_add( + bmain, workspace_old->id.name + 2, scene, + BKE_workspace_view_layer_get(workspace_old, scene), + &workspace_old->view_render); + ListBase *transform_orientations_old = BKE_workspace_transform_orientations_get(workspace_old); + ListBase *transform_orientations_new = BKE_workspace_transform_orientations_get(workspace_new); + + BLI_duplicatelist(transform_orientations_new, transform_orientations_old); + + workspace_new->tool = workspace_old->tool; + workspace_new->object_mode = workspace_old->object_mode; + + for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) { + WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace_new, layout_old, win); + + if (layout_active_old == layout_old) { + win->workspace_hook->temp_layout_store = layout_new; + } + } + return workspace_new; +} + +/** + * \return if succeeded. + */ +bool ED_workspace_delete( + WorkSpace *workspace, Main *bmain, bContext *C, wmWindowManager *wm) +{ + ID *workspace_id = (ID *)workspace; + + if (BLI_listbase_is_single(&bmain->workspaces)) { + return false; + } + + for (wmWindow *win = wm->windows.first; win; win = win->next) { + WorkSpace *prev = workspace_id->prev; + WorkSpace *next = workspace_id->next; + + ED_workspace_change((prev != NULL) ? prev : next, C, win); + } + BKE_libblock_free(bmain, workspace_id); + + return true; +} + +/** + * Some editor data may need to be synced with scene data (3D View camera and layers). + * This function ensures data is synced for editors in active layout of \a workspace. + */ +void ED_workspace_scene_data_sync( + WorkSpaceInstanceHook *hook, Scene *scene) +{ + bScreen *screen = BKE_workspace_active_screen_get(hook); + BKE_screen_view3d_scene_sync(screen, scene); +} + +void ED_workspace_view_layer_unset( + const Main *bmain, Scene *scene, + const ViewLayer *layer_unset, ViewLayer *layer_new) +{ + for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { + if (BKE_workspace_view_layer_get(workspace, scene) == layer_unset) { + BKE_workspace_view_layer_set(workspace, layer_new, scene); + } + } +} + +/** + * When a work-space mode has changed, + * flush it to all other visible work-spaces using the same object + * since we don't support one object being in two different modes at once. + * \note We could support this but it's more trouble than it's worth. + */ + +void ED_workspace_object_mode_sync_from_object(wmWindowManager *wm, WorkSpace *workspace, Object *obact) +{ + if (obact == NULL) { + return; + } + for (wmWindow *win = wm->windows.first; win; win = win->next) { + WorkSpace *workspace_iter = BKE_workspace_active_get(win->workspace_hook); + if ((workspace != workspace_iter) && (workspace->object_mode != workspace_iter->object_mode)) { + Scene *scene_iter = WM_window_get_active_scene(win); + ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene_iter, workspace_iter); + if (obact == OBACT(view_layer)) { + workspace_iter->object_mode = workspace->object_mode; + /* TODO(campbell), use msgbus */ + WM_main_add_notifier(NC_SCENE | ND_MODE | NS_MODE_OBJECT, scene_iter); + } + } + } +} + +void ED_workspace_object_mode_sync_from_scene(wmWindowManager *wm, WorkSpace *workspace, Scene *scene) +{ + ViewLayer *view_layer = BKE_workspace_view_layer_get(workspace, scene); + if (view_layer) { + Object *obact = OBACT(view_layer); + ED_workspace_object_mode_sync_from_object(wm, workspace, obact); + } +} + +bool ED_workspace_object_mode_in_other_window( + struct wmWindowManager *wm, const wmWindow *win_compare, Object *obact, + eObjectMode *r_object_mode) +{ + for (wmWindow *win_iter = wm->windows.first; win_iter; win_iter = win_iter->next) { + if (win_compare != win_iter) { + WorkSpace *workspace_iter = BKE_workspace_active_get(win_iter->workspace_hook); + Scene *scene_iter = WM_window_get_active_scene(win_iter); + ViewLayer *view_layer_iter = BKE_view_layer_from_workspace_get(scene_iter, workspace_iter); + Object *obact_iter = OBACT(view_layer_iter); + if (obact == obact_iter) { + if (r_object_mode) { + *r_object_mode = workspace_iter->object_mode; + } + return true; + } + } + } + + return false; +} + +/** \} Workspace API */ + + +/** \name Workspace Operators + * + * \{ */ + +static int workspace_new_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + wmWindow *win = CTX_wm_window(C); + WorkSpace *workspace = ED_workspace_duplicate(WM_window_get_active_workspace(win), bmain, win); + + WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace); + + return OPERATOR_FINISHED; +} + +static void WORKSPACE_OT_workspace_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "New Workspace"; + ot->description = "Add a new workspace"; + ot->idname = "WORKSPACE_OT_workspace_duplicate"; + + /* api callbacks */ + ot->exec = workspace_new_exec; + ot->poll = WM_operator_winactive; +} + +static int workspace_delete_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + + ED_workspace_delete(WM_window_get_active_workspace(win), bmain, C, wm); + + return OPERATOR_FINISHED; +} + +static void WORKSPACE_OT_workspace_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete Workspace"; + ot->description = "Delete the active workspace"; + ot->idname = "WORKSPACE_OT_workspace_delete"; + + /* api callbacks */ + ot->exec = workspace_delete_exec; +} + +static void workspace_config_file_path_from_folder_id( + const Main *bmain, int folder_id, char *r_path) +{ + const char *app_template = U.app_template[0] ? U.app_template : NULL; + const char * const cfgdir = BKE_appdir_folder_id(folder_id, app_template); + + if (cfgdir) { + BLI_make_file_string(bmain->name, r_path, cfgdir, BLENDER_WORKSPACES_FILE); + } + else { + r_path[0] = '\0'; + } +} + +ATTR_NONNULL(1) +static WorkspaceConfigFileData *workspace_config_file_read( + const Main *bmain, ReportList *reports) +{ + char workspace_config_path[FILE_MAX]; + bool has_path = false; + + workspace_config_file_path_from_folder_id(bmain, BLENDER_USER_CONFIG, workspace_config_path); + if (BLI_exists(workspace_config_path)) { + has_path = true; + } + else { + workspace_config_file_path_from_folder_id(bmain, BLENDER_DATAFILES, workspace_config_path); + if (BLI_exists(workspace_config_path)) { + has_path = true; + } + } + + return has_path ? BKE_blendfile_workspace_config_read(workspace_config_path, reports) : NULL; +} + +static void workspace_append_button( + uiLayout *layout, wmOperatorType *ot_append, const WorkSpace *workspace, const Main *from_main) +{ + const ID *id = (ID *)workspace; + PointerRNA opptr; + char lib_path[FILE_MAX_LIBEXTRA]; + + BLI_path_join( + lib_path, sizeof(lib_path), from_main->name, BKE_idcode_to_name(GS(id->name)), NULL); + + BLI_assert(STREQ(ot_append->idname, "WM_OT_append")); + uiItemFullO_ptr( + layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL, + WM_OP_EXEC_DEFAULT, 0, &opptr); + RNA_string_set(&opptr, "directory", lib_path); + RNA_string_set(&opptr, "filename", id->name + 2); + RNA_boolean_set(&opptr, "autoselect", false); +} + +ATTR_NONNULL(1, 2) +static void workspace_config_file_append_buttons( + uiLayout *layout, const Main *bmain, ReportList *reports) +{ + WorkspaceConfigFileData *workspace_config = workspace_config_file_read(bmain, reports); + + if (workspace_config) { + wmOperatorType *ot_append = WM_operatortype_find("WM_OT_append", true); + + for (WorkSpace *workspace = workspace_config->workspaces.first; workspace; workspace = workspace->id.next) { + workspace_append_button(layout, ot_append, workspace, workspace_config->main); + } + + BKE_blendfile_workspace_config_data_free(workspace_config); + } +} + +static int workspace_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + const Main *bmain = CTX_data_main(C); + + uiPopupMenu *pup = UI_popup_menu_begin(C, op->type->name, ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + uiItemO(layout, "Duplicate Current", ICON_NONE, "WORKSPACE_OT_workspace_duplicate"); + uiItemS(layout); + workspace_config_file_append_buttons(layout, bmain, op->reports); + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + +static void WORKSPACE_OT_workspace_add_menu(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Workspace"; + ot->description = "Add a new workspace by duplicating the current one or appending one " + "from the user configuration"; + ot->idname = "WORKSPACE_OT_workspace_add_menu"; + + /* api callbacks */ + ot->invoke = workspace_add_invoke; +} + +void ED_operatortypes_workspace(void) +{ + WM_operatortype_append(WORKSPACE_OT_workspace_duplicate); + WM_operatortype_append(WORKSPACE_OT_workspace_delete); + WM_operatortype_append(WORKSPACE_OT_workspace_add_menu); +} + +/** \} Workspace Operators */ diff --git a/source/blender/editors/screen/workspace_layout_edit.c b/source/blender/editors/screen/workspace_layout_edit.c new file mode 100644 index 00000000000..d84df160125 --- /dev/null +++ b/source/blender/editors/screen/workspace_layout_edit.c @@ -0,0 +1,197 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/screen/workspace_layout_edit.c + * \ingroup edscr + */ + +#include <stdlib.h> + +#include "BLI_utildefines.h" +#include "BLI_listbase.h" + +#include "DNA_screen_types.h" +#include "DNA_workspace_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_main.h" +#include "BKE_screen.h" +#include "BKE_workspace.h" + +#include "WM_api.h" + +#include "ED_screen.h" + +#include "screen_intern.h" + +/** + * Empty screen, with 1 dummy area without spacedata. Uses window size. + */ +WorkSpaceLayout *ED_workspace_layout_add( + WorkSpace *workspace, + wmWindow *win, + const char *name) +{ + const int winsize_x = WM_window_pixels_x(win); + const int winsize_y = WM_window_pixels_y(win); + + bScreen *screen = screen_add(name, winsize_x, winsize_y); + WorkSpaceLayout *layout = BKE_workspace_layout_add(workspace, screen, name); + + return layout; +} + +WorkSpaceLayout *ED_workspace_layout_duplicate( + WorkSpace *workspace, const WorkSpaceLayout *layout_old, + wmWindow *win) +{ + bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old); + const char *name = BKE_workspace_layout_name_get(layout_old); + bScreen *screen_new; + WorkSpaceLayout *layout_new; + + if (BKE_screen_is_fullscreen_area(screen_old)) { + return NULL; /* XXX handle this case! */ + } + + layout_new = ED_workspace_layout_add(workspace, win, name); + screen_new = BKE_workspace_layout_screen_get(layout_new); + screen_data_copy(screen_new, screen_old); + + return layout_new; +} + +static bool workspace_layout_delete_doit( + WorkSpace *workspace, WorkSpaceLayout *layout_old, WorkSpaceLayout *layout_new, + bContext *C) +{ + Main *bmain = CTX_data_main(C); + wmWindow *win = CTX_wm_window(C); + bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new); + + ED_screen_change(C, screen_new); + + if (BKE_workspace_active_layout_get(win->workspace_hook) != layout_old) { + BKE_workspace_layout_remove(bmain, workspace, layout_old); + return true; + } + + return false; +} + +bool workspace_layout_set_poll(const WorkSpaceLayout *layout) +{ + const bScreen *screen = BKE_workspace_layout_screen_get(layout); + + return ((BKE_screen_is_used(screen) == false) && + /* in typical usage temp screens should have a nonzero winid + * (all temp screens should be used, or closed & freed). */ + (screen->temp == false) && + (BKE_screen_is_fullscreen_area(screen) == false) && + (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT))); +} + +static WorkSpaceLayout *workspace_layout_delete_find_new(const WorkSpaceLayout *layout_old) +{ + for (WorkSpaceLayout *layout_new = layout_old->prev; layout_new; layout_new = layout_new->next) { + if (workspace_layout_set_poll(layout_new)) { + return layout_new; + } + } + + for (WorkSpaceLayout *layout_new = layout_old->next; layout_new; layout_new = layout_new->next) { + if (workspace_layout_set_poll(layout_new)) { + return layout_new; + } + } + + return NULL; +} + +/** + * \warning Only call outside of area/region loops! + * \return true if succeeded. + */ +bool ED_workspace_layout_delete( + WorkSpace *workspace, WorkSpaceLayout *layout_old, + bContext *C) +{ + const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old); + WorkSpaceLayout *layout_new; + + BLI_assert(BLI_findindex(BKE_workspace_layouts_get(workspace), layout_old) != -1); + + /* don't allow deleting temp fullscreens for now */ + if (BKE_screen_is_fullscreen_area(screen_old)) { + return false; + } + + /* A layout/screen can only be in use by one window at a time, so as + * long as we are able to find a layout/screen that is unused, we + * can safely assume ours is not in use anywhere an delete it. */ + + layout_new = workspace_layout_delete_find_new(layout_old); + + if (layout_new) { + return workspace_layout_delete_doit(workspace, layout_old, layout_new, C); + } + + return false; +} + +static bool workspace_layout_cycle_iter_cb(const WorkSpaceLayout *layout, void *UNUSED(arg)) +{ + /* return false to stop iterator when we have found a layout to activate */ + return !workspace_layout_set_poll(layout); +} + +bool ED_workspace_layout_cycle( + WorkSpace *workspace, const short direction, bContext *C) +{ + wmWindow *win = CTX_wm_window(C); + WorkSpaceLayout *old_layout = BKE_workspace_active_layout_get(win->workspace_hook); + WorkSpaceLayout *new_layout; + const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout); + ScrArea *sa = CTX_wm_area(C); + + if (old_screen->temp || (sa && sa->full && sa->full->temp)) { + return false; + } + + BLI_assert(ELEM(direction, 1, -1)); + new_layout = BKE_workspace_layout_iter_circular(workspace, old_layout, workspace_layout_cycle_iter_cb, + NULL, (direction == -1) ? true : false); + + if (new_layout && (old_layout != new_layout)) { + bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout); + + if (sa && sa->full) { + /* return to previous state before switching screens */ + ED_screen_full_restore(C, sa); /* may free screen of old_layout */ + } + + ED_screen_change(C, new_screen); + + return true; + } + + return false; +} |