Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/screen')
-rw-r--r--source/blender/editors/screen/CMakeLists.txt4
-rw-r--r--source/blender/editors/screen/area.c643
-rw-r--r--source/blender/editors/screen/glutil.c765
-rw-r--r--source/blender/editors/screen/screen_context.c167
-rw-r--r--source/blender/editors/screen/screen_draw.c316
-rw-r--r--source/blender/editors/screen/screen_edit.c534
-rw-r--r--source/blender/editors/screen/screen_intern.h13
-rw-r--r--source/blender/editors/screen/screen_ops.c263
-rw-r--r--source/blender/editors/screen/screendump.c31
-rw-r--r--source/blender/editors/screen/workspace_edit.c447
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c197
11 files changed, 1851 insertions, 1529 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 a53a16906d3..105fff38f62 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"
@@ -72,7 +75,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 */
@@ -88,23 +91,35 @@ 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);
+ immAttrib4ub(color, 0, 0, 0, 30);
+ immVertex2f(pos, rect.xmax, rect.ymin);
/* bottom */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin);
+ immAttrib4ub(color, 0, 0, 0, 30);
+ 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 */
+ immAttrib4ub(color, 255, 255, 255, 30);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+
+ immEnd();
+ immUnbindProgram();
glDisable(GL_BLEND);
}
@@ -112,11 +127,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) {
@@ -130,15 +145,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);
}
}
@@ -207,15 +222,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();
}
}
@@ -230,69 +257,102 @@ 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);
+ immAttrib4ub(col, 255, 255, 255, 180);
+ immVertex2f(pos, x2, y1);
+
+ immAttrib4ub(col, 255, 255, 255, 130);
+ immVertex2f(pos, x1, y2 - dy);
+ immAttrib4ub(col, 255, 255, 255, 130);
+ immVertex2f(pos, x2 - dx, y1);
+
+ immAttrib4ub(col, 255, 255, 255, 80);
+ immVertex2f(pos, x1, y2 - 2 * dy);
+ immAttrib4ub(col, 255, 255, 255, 80);
+ 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);
+ immAttrib4ub(col, 0, 0, 0, 210);
+ immVertex2f(pos, x2 + 1, y1);
+
+ immAttrib4ub(col, 0, 0, 0, 180);
+ immVertex2f(pos, x1, y2 - dy + 1);
+ immAttrib4ub(col, 0, 0, 0, 180);
+ immVertex2f(pos, x2 - dx + 1, y1);
+
+ immAttrib4ub(col, 0, 0, 0, 150);
+ immVertex2f(pos, x1, y2 - 2 * dy + 1);
+ immAttrib4ub(col, 0, 0, 0, 150);
+ 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)
@@ -315,54 +375,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;
}
@@ -373,24 +420,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;
}
@@ -412,10 +459,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 */
@@ -452,28 +499,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)
@@ -481,27 +538,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);
@@ -512,7 +557,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) {
@@ -529,9 +574,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
@@ -540,12 +589,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);
+ }
}
/* **********************************
@@ -656,7 +738,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;
@@ -1316,7 +1398,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 {
@@ -1349,24 +1433,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)
@@ -1440,6 +1514,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;
@@ -1458,7 +1533,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;
@@ -1472,14 +1547,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 */
@@ -1500,22 +1576,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);
}
@@ -1764,6 +1834,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;
@@ -1814,6 +1885,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);
@@ -1987,8 +2063,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 {
@@ -2092,22 +2172,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 */
@@ -2116,18 +2211,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);
@@ -2135,6 +2241,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[] =
@@ -2303,11 +2414,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);
@@ -2317,17 +2428,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);
@@ -2339,23 +2453,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)
@@ -2365,11 +2482,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);
@@ -2389,33 +2511,58 @@ 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);
+ fac = 0.0f;
+
+ /* the fine resolution level */
+ for (int i = 0; i < count_fine; i++) {
+ immAttrib3fv(color, theme_color);
+ immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
+ immAttrib3fv(color, theme_color);
+ immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
+ immAttrib3fv(color, theme_color);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
+ immAttrib3fv(color, theme_color);
+ 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);
+ fac = 0.0f;
+
+ /* the large resolution level */
+ for (int i = 0; i < count_large; i++) {
+ immAttrib3fv(color, theme_color);
+ immVertex2f(pos, x1, y1 * (1.0f - fac) + y2 * fac);
+ immAttrib3fv(color, theme_color);
+ immVertex2f(pos, x2, y1 * (1.0f - fac) + y2 * fac);
+ immAttrib3fv(color, theme_color);
+ immVertex2f(pos, x1 * (1.0f - fac) + x2 * fac, y1);
+ immAttrib3fv(color, theme_color);
+ 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 */
@@ -2452,8 +2599,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)
@@ -2469,9 +2619,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));
}
@@ -2479,17 +2633,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..cd875c73eda 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,25 +137,68 @@ 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);
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texid);
/* don't want nasty border artifacts */
@@ -401,18 +206,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 +219,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 +235,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 +243,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 +284,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 +295,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 +304,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 +371,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 +402,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 +418,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 +438,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 +461,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 +472,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 +502,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 +516,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 +528,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 +537,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 +558,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..98a6670d10f 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,14 @@ 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;
+ Object *obedit = view_layer ? OBEDIT_FROM_VIEW_LAYER(view_layer) : NULL;
if (CTX_data_dir(member)) {
CTX_data_dir_set(result, screen_context_dir);
@@ -116,84 +103,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);
}
}
}
@@ -345,8 +348,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;
}
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 62113cafebb..0b893d23e13 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"
@@ -134,7 +139,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;
}
@@ -544,8 +549,8 @@ int ED_operator_mask(bContext *C)
case SPACE_IMAGE:
{
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, view_layer);
}
}
}
@@ -553,6 +558,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);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -999,13 +1010,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! */
@@ -1031,11 +1046,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);
@@ -1289,6 +1308,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);
}
}
@@ -1584,7 +1605,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;
}
@@ -1853,7 +1876,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;
@@ -2176,12 +2199,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 &&
@@ -2496,64 +2518,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;
}
@@ -3397,7 +3371,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;
}
@@ -3590,6 +3564,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);
@@ -3700,10 +3676,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;
@@ -3783,11 +3761,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;
}
}
@@ -3796,11 +3774,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;
}
}
@@ -4058,11 +4036,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;
}
@@ -4087,9 +4067,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;
}
@@ -4107,103 +4089,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
* \{ */
@@ -4481,13 +4366,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..fbfb88ce6c1
--- /dev/null
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -0,0 +1,447 @@
+/*
+ * ***** 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;
+}
+
+/**
+ * Changes the object mode (if needed) to the one set in \a workspace_new.
+ * Object mode is still stored on object level. In future it should all be workspace level instead.
+ */
+static void workspace_change_update_mode(
+ const WorkSpace *workspace_old, const WorkSpace *workspace_new,
+ bContext *C, Object *ob_act, ReportList *reports)
+{
+ UNUSED_VARS(workspace_old, workspace_new, C, ob_act, reports);
+#if 0
+ eObjectMode mode_old = workspace_old->object_mode;
+ eObjectMode mode_new = workspace_new->object_mode;
+
+ if (mode_old != mode_new) {
+ ED_object_mode_compat_set(C, ob_act, mode_new, reports);
+ ED_object_mode_toggle(C, mode_new);
+ }
+#endif
+}
+
+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, wmWindowManager *wm)
+{
+ /* needs to be done before changing mode! (to ensure right context) */
+ workspace_change_update_view_layer(workspace_new, workspace_old, CTX_data_scene(C));
+ workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports);
+}
+
+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, wmWindowManager *wm, 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) {
+ 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 and updates context (including CTX_wm_workspace) */
+ screen_change_update(C, win, screen_new);
+ workspace_change_update(workspace_new, workspace_old, C, wm);
+
+ 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);
+
+ 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;
+
+ 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, wm, 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);
+ }
+ }
+}
+
+/** \} 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;
+}