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.txt5
-rw-r--r--source/blender/editors/screen/area.c1883
-rw-r--r--source/blender/editors/screen/glutil.c765
-rw-r--r--source/blender/editors/screen/screen_context.c327
-rw-r--r--source/blender/editors/screen/screen_draw.c454
-rw-r--r--source/blender/editors/screen/screen_edit.c1117
-rw-r--r--source/blender/editors/screen/screen_intern.h29
-rw-r--r--source/blender/editors/screen/screen_ops.c796
-rw-r--r--source/blender/editors/screen/screen_user_menu.c164
-rw-r--r--source/blender/editors/screen/screendump.c27
-rw-r--r--source/blender/editors/screen/workspace_edit.c508
-rw-r--r--source/blender/editors/screen/workspace_layout_edit.c199
12 files changed, 3751 insertions, 2523 deletions
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 43e044b613a..ee114eba3c5 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
@@ -45,7 +47,10 @@ set(SRC
screen_draw.c
screen_edit.c
screen_ops.c
+ screen_user_menu.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 6e4cbf27e28..d9851487569 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -41,24 +41,28 @@
#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 "WM_toolsystem.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,11 +76,17 @@
#include "screen_intern.h"
-extern void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3); /* xxx temp */
+enum RegionEmbossSide {
+ REGION_EMBOSS_LEFT = (1 << 0),
+ REGION_EMBOSS_TOP = (1 << 1),
+ REGION_EMBOSS_BOTTOM = (1 << 2),
+ REGION_EMBOSS_RIGHT = (1 << 3),
+ REGION_EMBOSS_ALL = REGION_EMBOSS_LEFT | REGION_EMBOSS_TOP | REGION_EMBOSS_RIGHT | REGION_EMBOSS_BOTTOM,
+};
/* general area and region code */
-static void region_draw_emboss(const ARegion *ar, const rcti *scirct)
+static void region_draw_emboss(const ARegion *ar, const rcti *scirct, int sides)
{
rcti rect;
@@ -88,35 +98,57 @@ 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);
+
+ float color[4] = {0.0f, 0.0f, 0.0f, 0.25f};
+ UI_GetThemeColor3fv(TH_EDITOR_OUTLINE, color);
- /* right */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmax, 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);
+ immUniformColor4fv(color);
+
+ immBeginAtMost(GWN_PRIM_LINES, 8);
+
+ /* right */
+ if (sides & REGION_EMBOSS_RIGHT) {
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymin);
+ }
+
+ /* bottom */
+ if (sides & REGION_EMBOSS_BOTTOM) {
+ immVertex2f(pos, rect.xmax, rect.ymin);
+ immVertex2f(pos, rect.xmin, rect.ymin);
+ }
- /* bottom */
- glColor4ub(0, 0, 0, 30);
- sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin);
+ /* left */
+ if (sides & REGION_EMBOSS_LEFT) {
+ immVertex2f(pos, rect.xmin, rect.ymin);
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ }
- /* top */
- glColor4ub(255, 255, 255, 30);
- sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax);
+ /* top */
+ if (sides & REGION_EMBOSS_TOP) {
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ }
- /* left */
- glColor4ub(255, 255, 255, 30);
- sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax);
+ immEnd();
+ immUnbindProgram();
glDisable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
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 +162,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);
}
}
@@ -172,11 +204,29 @@ void ED_area_azones_update(ScrArea *sa, const int mouse_xy[2])
break;
}
}
+ else if (az->type == AZONE_REGION_SCROLL) {
+ /* only if mouse is not hovering the azone */
+ if (BLI_rcti_isect_pt_v(&az->rect, mouse_xy) == false) {
+ View2D *v2d = &az->ar->v2d;
+
+ if (az->direction == AZ_SCROLL_VERT) {
+ az->alpha = v2d->alpha_vert = 0;
+ changed = true;
+ }
+ else if (az->direction == AZ_SCROLL_HOR) {
+ az->alpha = v2d->alpha_hor = 0;
+ changed = true;
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+ }
}
if (changed) {
sa->flag &= ~AREA_FLAG_ACTIONZONES_UPDATE;
- ED_area_tag_redraw(sa);
+ ED_area_tag_redraw_no_rebuild(sa);
}
}
@@ -207,82 +257,35 @@ 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;
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);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 0.0f, 0.0f, alpha);
+ imm_draw_box_wire_2d(pos, click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
+
+ immUniformColor4f(0.0f, 1.0f, 1.0f, alpha);
+ 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();
}
}
/**
* \brief Corner widgets use for dragging and splitting the view.
*/
-static void area_draw_azone(short x1, short y1, short x2, short y2)
+static void area_draw_azone(short UNUSED(x1), short UNUSED(y1), short UNUSED(x2), short UNUSED(y2))
{
- int dx = x2 - x1;
- int dy = y2 - y1;
-
- dx = copysign(ceilf(0.3f * abs(dx)), dx);
- dy = copysign(ceilf(0.3f * abs(dy)), dy);
-
- glEnable(GL_BLEND);
- glEnable(GL_LINE_SMOOTH);
-
- 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);
-
- 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);
-
- glColor4f(1.f, 1.f, 1.f, 0.8f);
-
- gluQuadricDrawStyle(qobj, GLU_FILL);
- gluDisk(qobj, 0.0, 4.25f, 16, 1);
-
- 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);
+ /* No drawing needed since all corners are action zone, and visually distinguishable. */
}
static void draw_azone_plus(float x1, float y1, float x2, float y2)
@@ -290,9 +293,19 @@ 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,87 +328,10 @@ 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];
-
- glEnable(GL_BLEND);
- UI_GetThemeColor3fv(TH_HEADER, col);
- glColor4f(col[0], col[1], col[2], 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);
- 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);
- 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);
- 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);
- break;
- }
-
- glDisable(GL_BLEND);
-}
-
-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);
-
- /* 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);
- 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);
- 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);
- 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);
- break;
-
- }
-
- glDisable(GL_BLEND);
}
static void area_azone_tag_update(ScrArea *sa)
@@ -412,10 +348,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 */
@@ -427,18 +363,10 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
area_draw_azone(az->x1, az->y1, az->x2, az->y2);
}
else if (az->type == AZONE_REGION) {
-
if (az->ar) {
/* only display tab or icons when the region is hidden */
if (az->ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- if (G.debug_value == 3)
- region_draw_azone_icon(az);
- else if (G.debug_value == 2)
- region_draw_azone_tria(az);
- else if (G.debug_value == 1)
- region_draw_azone_tab(az);
- else
- region_draw_azone_tab_plus(az);
+ region_draw_azone_tab_plus(az);
}
}
}
@@ -449,59 +377,84 @@ static void region_draw_azones(ScrArea *sa, ARegion *ar)
area_azone_tag_update(sa);
}
}
+ else if (az->type == AZONE_REGION_SCROLL) {
+ if (az->alpha != 0.0f) {
+ area_azone_tag_update(sa);
+ }
+ /* Don't draw this azone. */
+ }
}
}
- glPopMatrix();
+ gpuPopMatrix();
glDisable(GL_BLEND);
}
+/* Follow wmMsgNotifyFn spec */
+void ED_region_do_msg_notify_tag_redraw(
+ bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ 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 */
-/* makes region ready for drawing, sets pixelspace */
-void ED_region_set(const bContext *C, ARegion *ar)
+void ED_region_do_layout(bContext *C, ARegion *ar)
{
- wmWindow *win = CTX_wm_window(C);
+ /* This is optional, only needed for dynamically sized regions. */
ScrArea *sa = CTX_wm_area(C);
+ ARegionType *at = ar->type;
- ar->drawrct = ar->winrct;
+ if (!at->layout) {
+ return;
+ }
- /* note; this sets state, so we can use wmOrtho and friends */
- wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, true);
+ if (at->do_lock) {
+ return;
+ }
- UI_SetTheme(sa ? sa->spacetype : 0, ar->type ? ar->type->regionid : 0);
+ ar->do_draw |= RGN_DRAWING;
- ED_region_pixelspace(ar);
+ UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
+ at->layout(C, ar);
}
-
/* only exported for WM */
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 +465,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 +482,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,11 +497,46 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
UI_blocklist_free_inactive(C, &ar->uiblocks);
if (sa) {
- /* 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) {
- region_draw_emboss(ar, &ar->winrct);
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ /* Only draw region emboss for top-bar and quad-view. */
+ if ((screen->state != SCREENFULL) && ED_area_is_global(sa)) {
+ region_draw_emboss(ar, &ar->winrct, (REGION_EMBOSS_LEFT | REGION_EMBOSS_RIGHT));
+ }
+ else if ((ar->regiontype == RGN_TYPE_WINDOW) && (ar->alignment == RGN_ALIGN_QSPLIT)) {
+ region_draw_emboss(ar, &ar->winrct, REGION_EMBOSS_ALL);
+ }
+ }
+
+ /* 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);
}
}
@@ -559,7 +551,7 @@ void ED_region_tag_redraw(ARegion *ar)
* but python scripts can cause this to happen indirectly */
if (ar && !(ar->do_draw & RGN_DRAWING)) {
/* zero region means full region redraw */
- ar->do_draw &= ~RGN_DRAW_PARTIAL;
+ ar->do_draw &= ~(RGN_DRAW_PARTIAL | RGN_DRAW_NO_REBUILD);
ar->do_draw |= RGN_DRAW;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
@@ -571,6 +563,15 @@ void ED_region_tag_redraw_overlay(ARegion *ar)
ar->do_draw_overlay = RGN_DRAW;
}
+void ED_region_tag_redraw_no_rebuild(ARegion *ar)
+{
+ if (ar && !(ar->do_draw & (RGN_DRAWING | RGN_DRAW))) {
+ ar->do_draw &= ~RGN_DRAW_PARTIAL;
+ ar->do_draw |= RGN_DRAW_NO_REBUILD;
+ memset(&ar->drawrct, 0, sizeof(ar->drawrct));
+ }
+}
+
void ED_region_tag_refresh_ui(ARegion *ar)
{
if (ar) {
@@ -581,7 +582,7 @@ void ED_region_tag_refresh_ui(ARegion *ar)
void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
- if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) {
+ if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD | RGN_DRAW_PARTIAL))) {
/* no redraw set yet, set partial region */
ar->do_draw |= RGN_DRAW_PARTIAL;
ar->drawrct = *rct;
@@ -592,7 +593,7 @@ void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct)
BLI_rcti_union(&ar->drawrct, rct);
}
else {
- BLI_assert((ar->do_draw & RGN_DRAW) != 0);
+ BLI_assert((ar->do_draw & (RGN_DRAW | RGN_DRAW_NO_REBUILD)) != 0);
/* Else, full redraw is already requested, nothing to do here. */
}
}
@@ -607,6 +608,15 @@ void ED_area_tag_redraw(ScrArea *sa)
ED_region_tag_redraw(ar);
}
+void ED_area_tag_redraw_no_rebuild(ScrArea *sa)
+{
+ ARegion *ar;
+
+ if (sa)
+ for (ar = sa->regionbase.first; ar; ar = ar->next)
+ ED_region_tag_redraw_no_rebuild(ar);
+}
+
void ED_area_tag_redraw_regiontype(ScrArea *sa, int regiontype)
{
ARegion *ar;
@@ -656,7 +666,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;
@@ -671,39 +681,62 @@ static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
return;
}
- /* can't click on bottom corners on OS X, already used for resizing */
+ if (ED_area_is_global(sa)) {
+ return;
+ }
+
+ float coords[4][4] = {
+ /* Bottom-left. */
+ {sa->totrct.xmin,
+ sa->totrct.ymin,
+ sa->totrct.xmin + (AZONESPOT - 1),
+ sa->totrct.ymin + (AZONESPOT - 1)},
+ /* Bottom-right. */
+ {sa->totrct.xmax,
+ sa->totrct.ymin,
+ sa->totrct.xmax - (AZONESPOT - 1),
+ sa->totrct.ymin + (AZONESPOT - 1)},
+ /* Top-left. */
+ {sa->totrct.xmin,
+ sa->totrct.ymax,
+ sa->totrct.xmin + (AZONESPOT - 1),
+ sa->totrct.ymax - (AZONESPOT - 1)},
+ /* Top-right. */
+ {sa->totrct.xmax,
+ sa->totrct.ymax,
+ sa->totrct.xmax - (AZONESPOT - 1),
+ sa->totrct.ymax - (AZONESPOT - 1)}};
+
+ for (int i = 0; i < 4; i++) {
+ /* can't click on bottom corners on OS X, already used for resizing */
#ifdef __APPLE__
- if (!(sa->totrct.xmin == 0 && sa->totrct.ymin == 0) || WM_window_is_fullscreen(win))
+ if (!WM_window_is_fullscreen(win) &&
+ ((coords[i][0] == 0 && coords[i][1] == 0) ||
+ (coords[i][0] == WM_window_pixels_x(win) && coords[i][1] == 0)))
+ {
+ continue;
+ }
#else
- (void)win;
+ (void)win;
#endif
- {
+
/* set area action zones */
az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
BLI_addtail(&(sa->actionzones), az);
az->type = AZONE_AREA;
- az->x1 = sa->totrct.xmin;
- az->y1 = sa->totrct.ymin;
- az->x2 = sa->totrct.xmin + (AZONESPOT - 1);
- az->y2 = sa->totrct.ymin + (AZONESPOT - 1);
+ az->x1 = coords[i][0];
+ az->y1 = coords[i][1];
+ az->x2 = coords[i][2];
+ az->y2 = coords[i][3];
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-
- az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
- az->type = AZONE_AREA;
- az->x1 = sa->totrct.xmax;
- az->y1 = sa->totrct.ymax;
- az->x2 = sa->totrct.xmax - (AZONESPOT - 1);
- az->y2 = sa->totrct.ymax - (AZONESPOT - 1);
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
static void fullscreen_azone_initialize(ScrArea *sa, ARegion *ar)
{
AZone *az;
- if (ar->regiontype != RGN_TYPE_WINDOW)
+ if (ED_area_is_global(sa) || (ar->regiontype != RGN_TYPE_WINDOW))
return;
az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
@@ -753,65 +786,6 @@ static void region_azone_edge(AZone *az, ARegion *ar)
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-static void region_azone_icon(ScrArea *sa, AZone *az, ARegion *ar)
-{
- AZone *azt;
- int tot = 0;
-
- /* count how many actionzones with along same edge are available.
- * This allows for adding more action zones in the future without
- * having to worry about correct offset */
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (azt->edge == az->edge) tot++;
- }
-
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- az->x1 = ar->winrct.xmax - tot * 2 * AZONEPAD_ICON;
- az->y1 = ar->winrct.ymax + AZONEPAD_ICON;
- az->x2 = ar->winrct.xmax - tot * AZONEPAD_ICON;
- az->y2 = ar->winrct.ymax + 2 * AZONEPAD_ICON;
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmin + AZONEPAD_ICON;
- az->y1 = ar->winrct.ymin - 2 * AZONEPAD_ICON;
- az->x2 = ar->winrct.xmin + 2 * AZONEPAD_ICON;
- az->y2 = ar->winrct.ymin - AZONEPAD_ICON;
- break;
- case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin - 2 * AZONEPAD_ICON;
- az->y1 = ar->winrct.ymax - tot * 2 * AZONEPAD_ICON;
- az->x2 = ar->winrct.xmin - AZONEPAD_ICON;
- az->y2 = ar->winrct.ymax - tot * AZONEPAD_ICON;
- break;
- case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax + AZONEPAD_ICON;
- az->y1 = ar->winrct.ymax - tot * 2 * AZONEPAD_ICON;
- az->x2 = ar->winrct.xmax + 2 * AZONEPAD_ICON;
- az->y2 = ar->winrct.ymax - tot * AZONEPAD_ICON;
- break;
- }
-
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
-
- /* if more azones on 1 spot, set offset */
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (az != azt) {
- if (ABS(az->x1 - azt->x1) < 2 && ABS(az->y1 - azt->y1) < 2) {
- if (az->edge == AE_TOP_TO_BOTTOMRIGHT || az->edge == AE_BOTTOM_TO_TOPLEFT) {
- az->x1 += AZONESPOT;
- az->x2 += AZONESPOT;
- }
- else {
- az->y1 -= AZONESPOT;
- az->y2 -= AZONESPOT;
- }
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
- }
- }
- }
-}
-
#define AZONEPAD_TAB_PLUSW (0.7f * U.widget_unit)
#define AZONEPAD_TAB_PLUSH (0.7f * U.widget_unit)
@@ -856,143 +830,99 @@ static void region_azone_tab_plus(ScrArea *sa, AZone *az, ARegion *ar)
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-
-#define AZONEPAD_TABW (0.9f * U.widget_unit)
-#define AZONEPAD_TABH (0.35f * U.widget_unit)
-
-/* region already made zero sized, in shape of edge */
-static void region_azone_tab(ScrArea *sa, AZone *az, ARegion *ar)
+static void region_azone_edge_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
{
- AZone *azt;
- int tot = 0, add;
+ AZone *az = NULL;
+ const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL));
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (azt->edge == az->edge) tot++;
+ if (is_hidden && is_fullscreen) {
+ return;
}
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
- az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TABW;
- az->y1 = ar->winrct.ymax - add;
- az->x2 = ar->winrct.xmax - AZONEPAD_TABW;
- az->y2 = ar->winrct.ymax - add + AZONEPAD_TABH;
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmin + AZONEPAD_TABW;
- az->y1 = ar->winrct.ymin - AZONEPAD_TABH;
- az->x2 = ar->winrct.xmin + 2 * AZONEPAD_TABW;
- az->y2 = ar->winrct.ymin;
- break;
- case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin + 1 - AZONEPAD_TABH;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TABW;
- az->x2 = ar->winrct.xmin + 1;
- az->y2 = ar->winrct.ymax - AZONEPAD_TABW;
- break;
- case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax - 1;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TABW;
- az->x2 = ar->winrct.xmax - 1 + AZONEPAD_TABH;
- az->y2 = ar->winrct.ymax - AZONEPAD_TABW;
- break;
+ az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
+ BLI_addtail(&(sa->actionzones), az);
+ az->type = AZONE_REGION;
+ az->ar = ar;
+ az->edge = edge;
+
+ if (is_hidden) {
+ region_azone_tab_plus(sa, az, ar);
+ }
+ else if (!is_hidden && (ar->regiontype != RGN_TYPE_HEADER)) {
+ region_azone_edge(az, ar);
}
- /* rect needed for mouse pointer test */
- BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-#define AZONEPAD_TRIAW (0.8f * U.widget_unit)
-#define AZONEPAD_TRIAH (0.45f * U.widget_unit)
-
-
-/* region already made zero sized, in shape of edge */
-static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
+static void region_azone_scrollbar_initialize(ScrArea *sa, ARegion *ar, AZScrollDirection direction)
{
- AZone *azt;
- int tot = 0, add;
+ rcti scroller_vert = (direction == AZ_SCROLL_VERT) ? ar->v2d.vert : ar->v2d.hor;
+ AZone *az = MEM_callocN(sizeof(*az), __func__);
- for (azt = sa->actionzones.first; azt; azt = azt->next) {
- if (azt->edge == az->edge) tot++;
- }
+ BLI_addtail(&sa->actionzones, az);
+ az->type = AZONE_REGION_SCROLL;
+ az->ar = ar;
+ az->direction = direction;
- switch (az->edge) {
- case AE_TOP_TO_BOTTOMRIGHT:
- add = (ar->winrct.ymax == sa->totrct.ymin) ? 1 : 0;
- az->x1 = ar->winrct.xmax - 2 * AZONEPAD_TRIAW;
- az->y1 = ar->winrct.ymax - add;
- az->x2 = ar->winrct.xmax - AZONEPAD_TRIAW;
- az->y2 = ar->winrct.ymax - add + AZONEPAD_TRIAH;
- break;
- case AE_BOTTOM_TO_TOPLEFT:
- az->x1 = ar->winrct.xmin + AZONEPAD_TRIAW;
- az->y1 = ar->winrct.ymin - AZONEPAD_TRIAH;
- az->x2 = ar->winrct.xmin + 2 * AZONEPAD_TRIAW;
- az->y2 = ar->winrct.ymin;
- break;
- case AE_LEFT_TO_TOPRIGHT:
- az->x1 = ar->winrct.xmin + 1 - AZONEPAD_TRIAH;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TRIAW;
- az->x2 = ar->winrct.xmin + 1;
- az->y2 = ar->winrct.ymax - AZONEPAD_TRIAW;
- break;
- case AE_RIGHT_TO_TOPLEFT:
- az->x1 = ar->winrct.xmax - 1;
- az->y1 = ar->winrct.ymax - 2 * AZONEPAD_TRIAW;
- az->x2 = ar->winrct.xmax - 1 + AZONEPAD_TRIAH;
- az->y2 = ar->winrct.ymax - AZONEPAD_TRIAW;
- break;
+ if (direction == AZ_SCROLL_VERT) {
+ az->ar->v2d.alpha_vert = 0;
}
- /* rect needed for mouse pointer test */
+ else if (direction == AZ_SCROLL_HOR) {
+ az->ar->v2d.alpha_hor = 0;
+ }
+
+ BLI_rcti_translate(&scroller_vert, ar->winrct.xmin, ar->winrct.ymin);
+ az->x1 = scroller_vert.xmin - AZONEFADEIN;
+ az->y1 = scroller_vert.ymin - AZONEFADEIN;
+ az->x2 = scroller_vert.xmax + AZONEFADEIN;
+ az->y2 = scroller_vert.ymax + AZONEFADEIN;
+
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
-
-static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
+static void region_azones_scrollbars_initialize(ScrArea *sa, ARegion *ar)
{
- AZone *az = NULL;
- const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) == 0;
+ const View2D *v2d = &ar->v2d;
- if (is_hidden || !is_fullscreen) {
- az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
- az->type = AZONE_REGION;
- az->ar = ar;
- az->edge = edge;
+ if ((v2d->scroll & V2D_SCROLL_VERTICAL) && ((v2d->scroll & V2D_SCROLL_SCALE_VERTICAL) == 0)) {
+ region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_VERT);
}
-
- if (!is_hidden) {
- if (!is_fullscreen) {
- if (G.debug_value == 3)
- region_azone_icon(sa, az, ar);
- else if (G.debug_value == 2)
- region_azone_tria(sa, az, ar);
- else if (G.debug_value == 1)
- region_azone_tab(sa, az, ar);
- else
- region_azone_tab_plus(sa, az, ar);
- }
+ if ((v2d->scroll & V2D_SCROLL_HORIZONTAL) && ((v2d->scroll & V2D_SCROLL_SCALE_HORIZONTAL) == 0)) {
+ region_azone_scrollbar_initialize(sa, ar, AZ_SCROLL_HOR);
}
- else {
- region_azone_edge(az, ar);
- }
-
}
/* *************************************************************** */
-static void region_azone_add(ScrArea *sa, ARegion *ar, const int alignment, const bool is_fullscreen)
+static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *ar, const int alignment)
{
+ const bool is_fullscreen = screen->state == SCREENFULL;
+
/* edge code (t b l r) is along which area edge azone will be drawn */
- if (alignment == RGN_ALIGN_TOP)
- region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
+ if (ar->regiontype == RGN_TYPE_HEADER && ar->winy + 6 > sa->winy) {
+ /* The logic for this is: when the header takes up the full area,
+ * disallow hiding it to view the main window.
+ *
+ * Without this, you can drag down the file selectors header and hide it
+ * by accident very easily (highly annoying!), the value 6 is arbitrary
+ * but accounts for small common rounding problems when scaling the UI,
+ * must be minimum '4' */
+ }
+ else if (alignment == RGN_ALIGN_TOP)
+ region_azone_edge_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
else if (alignment == RGN_ALIGN_BOTTOM)
- region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
+ region_azone_edge_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_RIGHT)
- region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
+ region_azone_edge_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_LEFT)
- region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
+ region_azone_edge_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
+
+ if (is_fullscreen) {
+ fullscreen_azone_initialize(sa, ar);
+ }
+
+ region_azones_scrollbars_initialize(sa, ar);
}
/* dir is direction to check, not the splitting edge direction! */
@@ -1018,7 +948,14 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
/* find overlapping previous region on same place */
for (ar1 = ar->prev; ar1; ar1 = ar1->prev) {
+ if (ar1->flag & (RGN_FLAG_HIDDEN)) {
+ continue;
+ }
+
if (ar1->overlap && ((ar1->alignment & RGN_SPLIT_PREV) == 0)) {
+ if (ELEM(ar1->alignment, RGN_ALIGN_FLOAT)) {
+ continue;
+ }
align1 = ar1->alignment;
if (BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) {
if (align1 != align) {
@@ -1057,6 +994,13 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
/* At this point, 'ar' is in its final position and still open.
* Make a final check it does not overlap any previous 'other side' region. */
for (ar1 = ar->prev; ar1; ar1 = ar1->prev) {
+ if (ar1->flag & (RGN_FLAG_HIDDEN)) {
+ continue;
+ }
+ if (ELEM(ar1->alignment, RGN_ALIGN_FLOAT)) {
+ continue;
+ }
+
if (ar1->overlap && (ar1->alignment & RGN_SPLIT_PREV) == 0) {
if ((ar1->alignment != align) && BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) {
/* Left overlapping right or vice-versa, forbid this! */
@@ -1068,16 +1012,22 @@ static void region_overlap_fix(ScrArea *sa, ARegion *ar)
}
/* overlapping regions only in the following restricted cases */
-static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
+bool ED_region_is_overlap(int spacetype, int regiontype)
{
+ if (regiontype == RGN_TYPE_HUD) {
+ return 1;
+ }
if (U.uiflag2 & USER_REGION_OVERLAP) {
- if (WM_is_draw_triple(win)) {
- if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
- if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
+ if (ELEM(spacetype, SPACE_VIEW3D, SPACE_SEQ, SPACE_IMAGE)) {
+ if (ELEM(regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
+ return 1;
+
+ if (ELEM(spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
+ if (regiontype == RGN_TYPE_HEADER)
return 1;
}
- else if (sa->spacetype == SPACE_IMAGE) {
- if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
+ else if (spacetype == SPACE_SEQ) {
+ if (regiontype == RGN_TYPE_PREVIEW)
return 1;
}
}
@@ -1086,7 +1036,7 @@ static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
return 0;
}
-static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti *remainder, int quad)
+static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti *remainder, rcti *overlap_remainder, int quad)
{
rcti *remainder_prev = remainder;
int prefsizex, prefsizey;
@@ -1106,20 +1056,24 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
alignment = ar->alignment & ~RGN_SPLIT_PREV;
/* set here, assuming userpref switching forces to call this again */
- ar->overlap = region_is_overlap(win, sa, ar);
+ ar->overlap = ED_region_is_overlap(sa->spacetype, ar->regiontype);
/* clear state flags first */
ar->flag &= ~RGN_FLAG_TOO_SMALL;
/* user errors */
- if (ar->next == NULL && alignment != RGN_ALIGN_QSPLIT)
+ if ((ar->next == NULL) && !ELEM(alignment, RGN_ALIGN_QSPLIT, RGN_ALIGN_FLOAT)) {
alignment = RGN_ALIGN_NONE;
+ }
- /* prefsize, for header we stick to exception (prevent dpi rounding error) */
- prefsizex = UI_DPI_FAC * (ar->sizex > 1 ? ar->sizex + 0.5f : ar->type->prefsizex);
+ /* prefsize, taking into account DPI */
+ prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex);
if (ar->regiontype == RGN_TYPE_HEADER) {
prefsizey = ED_area_headersize();
}
+ else if (ED_area_is_global(sa)) {
+ prefsizey = ED_region_global_size_y();
+ }
else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) {
prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2);
}
@@ -1132,7 +1086,28 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
/* hidden is user flag */
}
else if (alignment == RGN_ALIGN_FLOAT) {
- /* XXX floating area region, not handled yet here */
+ /**
+ * \note Currently this window type is only used for #RGN_TYPE_HUD,
+ * We expect the panel to resize it's self to be larger.
+ *
+ * This aligns to the lower left of the area.
+ */
+ rcti overlap_remainder_margin = *overlap_remainder;
+ BLI_rcti_resize(
+ &overlap_remainder_margin,
+ max_ii(0, BLI_rcti_size_x(overlap_remainder) - UI_UNIT_X / 2),
+ max_ii(0, BLI_rcti_size_y(overlap_remainder) - UI_UNIT_Y / 2));
+ ar->winrct.xmin = overlap_remainder_margin.xmin;
+ ar->winrct.ymin = overlap_remainder_margin.ymin;
+ ar->winrct.xmax = ar->winrct.xmin + ar->sizex - 1;
+ ar->winrct.ymax = ar->winrct.ymin + ar->sizey - 1;
+
+ BLI_rcti_isect(&ar->winrct, &overlap_remainder_margin, &ar->winrct);
+ if (BLI_rcti_size_x(&ar->winrct) < UI_UNIT_X ||
+ BLI_rcti_size_y(&ar->winrct) < UI_UNIT_Y)
+ {
+ ar->flag |= RGN_FLAG_TOO_SMALL;
+ }
}
else if (rct_fits(remainder, 'v', 1) < 0 || rct_fits(remainder, 'h', 1) < 0) {
/* remainder is too small for any usage */
@@ -1144,50 +1119,50 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
BLI_rcti_init(remainder, 0, 0, 0, 0);
}
else if (alignment == RGN_ALIGN_TOP || alignment == RGN_ALIGN_BOTTOM) {
+ rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(remainder, 'v', prefsizey) < 0) {
+ if (rct_fits(winrct, 'v', prefsizey) < 0) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
- int fac = rct_fits(remainder, 'v', prefsizey);
+ int fac = rct_fits(winrct, 'v', prefsizey);
if (fac < 0)
prefsizey += fac;
- ar->winrct = *remainder;
+ ar->winrct = *winrct;
if (alignment == RGN_ALIGN_TOP) {
ar->winrct.ymin = ar->winrct.ymax - prefsizey + 1;
- remainder->ymax = ar->winrct.ymin - 1;
+ winrct->ymax = ar->winrct.ymin - 1;
}
else {
ar->winrct.ymax = ar->winrct.ymin + prefsizey - 1;
- remainder->ymin = ar->winrct.ymax + 1;
+ winrct->ymin = ar->winrct.ymax + 1;
}
}
}
else if (ELEM(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ rcti *winrct = (ar->overlap) ? overlap_remainder : remainder;
- if (rct_fits(remainder, 'h', prefsizex) < 0) {
+ if (rct_fits(winrct, 'h', prefsizex) < 0) {
ar->flag |= RGN_FLAG_TOO_SMALL;
}
else {
- int fac = rct_fits(remainder, 'h', prefsizex);
+ int fac = rct_fits(winrct, 'h', prefsizex);
if (fac < 0)
prefsizex += fac;
- ar->winrct = *remainder;
+ ar->winrct = *winrct;
if (alignment == RGN_ALIGN_RIGHT) {
ar->winrct.xmin = ar->winrct.xmax - prefsizex + 1;
- if (ar->overlap == 0)
- remainder->xmax = ar->winrct.xmin - 1;
+ winrct->xmax = ar->winrct.xmin - 1;
}
else {
ar->winrct.xmax = ar->winrct.xmin + prefsizex - 1;
- if (ar->overlap == 0)
- remainder->xmin = ar->winrct.xmax + 1;
+ winrct->xmin = ar->winrct.xmax + 1;
}
}
}
@@ -1271,12 +1246,13 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
if (ar->winy > 1) ar->sizey = (ar->winy + 0.5f) / UI_DPI_FAC;
/* exception for multiple overlapping regions on same spot */
- if (ar->overlap)
+ if (ar->overlap & (alignment != RGN_ALIGN_FLOAT)) {
region_overlap_fix(sa, ar);
+ }
/* set winrect for azones */
if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- ar->winrct = *remainder;
+ ar->winrct = (ar->overlap) ? *overlap_remainder : *remainder;
switch (alignment) {
case RGN_ALIGN_TOP:
@@ -1305,42 +1281,46 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
}
}
- /* in end, add azones, where appropriate */
- if (ar->regiontype == RGN_TYPE_HEADER && ar->winy + 6 > sa->winy) {
- /* The logic for this is: when the header takes up the full area,
- * disallow hiding it to view the main window.
- *
- * Without this, you can drag down the file selectors header and hide it
- * by accident very easily (highly annoying!), the value 6 is arbitrary
- * but accounts for small common rounding problems when scaling the UI,
- * must be minimum '4' */
- }
- else {
- if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
- region_azone_add(sa, ar, alignment, false);
- }
- else {
- region_azone_add(sa, ar, alignment, true);
- fullscreen_azone_initialize(sa, ar);
- }
+ /* After non-overlapping region, all following overlapping regions
+ * fit within the remaining space again. */
+ if (!ar->overlap) {
+ *overlap_remainder = *remainder;
}
- region_rect_recursive(win, sa, ar->next, remainder, quad);
+ region_rect_recursive(win, sa, ar->next, remainder, overlap_remainder, quad);
}
-static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
+static void area_calc_totrct(ScrArea *sa, const rcti *window_rect)
{
- short rt = (short) U.pixelsize;
+ short px = (short)U.pixelsize;
- if (sa->v1->vec.x > 0) sa->totrct.xmin = sa->v1->vec.x + rt;
- else sa->totrct.xmin = sa->v1->vec.x;
- if (sa->v4->vec.x < sizex - 1) sa->totrct.xmax = sa->v4->vec.x - rt;
- else sa->totrct.xmax = sa->v4->vec.x;
+ sa->totrct.xmin = sa->v1->vec.x;
+ sa->totrct.xmax = sa->v4->vec.x;
+ sa->totrct.ymin = sa->v1->vec.y;
+ sa->totrct.ymax = sa->v2->vec.y;
- if (sa->v1->vec.y > 0) sa->totrct.ymin = sa->v1->vec.y + rt;
- else sa->totrct.ymin = sa->v1->vec.y;
- if (sa->v2->vec.y < sizey - 1) sa->totrct.ymax = sa->v2->vec.y - rt;
- else sa->totrct.ymax = sa->v2->vec.y;
+ /* scale down totrct by 1 pixel on all sides not matching window borders */
+ if (sa->totrct.xmin > window_rect->xmin) {
+ sa->totrct.xmin += px;
+ }
+ if (sa->totrct.xmax < (window_rect->xmax - 1)) {
+ sa->totrct.xmax -= px;
+ }
+ if (sa->totrct.ymin > window_rect->ymin) {
+ sa->totrct.ymin += px;
+ }
+ if (sa->totrct.ymax < (window_rect->ymax - 1)) {
+ sa->totrct.ymax -= px;
+ }
+ /* Although the following asserts are correct they lead to a very unstable Blender.
+ * And the asserts would fail even in 2.7x (they were added in 2.8x as part of the top-bar commit).
+ * For more details see T54864. */
+#if 0
+ BLI_assert(sa->totrct.xmin >= 0);
+ BLI_assert(sa->totrct.xmax >= 0);
+ BLI_assert(sa->totrct.ymin >= 0);
+ BLI_assert(sa->totrct.ymax >= 0);
+#endif
/* for speedup */
sa->winx = BLI_rcti_size_x(&sa->totrct) + 1;
@@ -1349,24 +1329,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)
@@ -1390,19 +1360,15 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* time-markers */
wmKeyMap *keymap = WM_keymap_find(wm->defaultconf, "Markers", 0, 0);
- /* time space only has this keymap, the others get a boundbox restricted map */
- if (sa->spacetype != SPACE_TIME) {
- ARegion *ar;
- /* same local check for all areas */
- static rcti rect = {0, 10000, 0, -1};
- rect.ymax = UI_MARKER_MARGIN_Y;
- ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar) {
- WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
- }
+ /* use a boundbox restricted map */
+ ARegion *ar;
+ /* same local check for all areas */
+ static rcti rect = {0, 10000, 0, -1};
+ rect.ymax = UI_MARKER_MARGIN_Y;
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar) {
+ WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
}
- else
- WM_event_add_keymap_handler(handlers, keymap);
}
if (flag & ED_KEYMAP_ANIMATION) {
/* frame changing and timeline operators (for time spaces) */
@@ -1436,18 +1402,55 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
}
}
+void ED_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area)
+{
+ rcti rect, overlap_rect;
+ rcti window_rect;
+
+ if (!(area->flag & AREA_FLAG_REGION_SIZE_UPDATE)) {
+ return;
+ }
+
+ WM_window_rect_calc(win, &window_rect);
+ area_calc_totrct(area, &window_rect);
+
+ /* region rect sizes */
+ rect = area->totrct;
+ overlap_rect = rect;
+ region_rect_recursive(win, area, area->regionbase.first, &rect, &overlap_rect, 0);
+
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
+ region_subwindow(ar);
+
+ /* region size may have changed, init does necessary adjustments */
+ if (ar->type->init) {
+ ar->type->init(wm, ar);
+ }
+ }
+
+ area->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
+}
/* called in screen_refresh, or screens_init, also area size changes */
void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
{
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ Scene *scene = WM_window_get_active_scene(win);
ARegion *ar;
- rcti rect;
+ rcti rect, overlap_rect;
+ rcti window_rect;
+
+ if (ED_area_is_global(sa) && (sa->global->flag & GLOBAL_AREA_IS_HIDDEN)) {
+ return;
+ }
+ WM_window_rect_calc(win, &window_rect);
/* set typedefinitions */
sa->type = BKE_spacetype_from_id(sa->spacetype);
if (sa->type == NULL) {
- sa->butspacetype = sa->spacetype = SPACE_VIEW3D;
+ sa->spacetype = SPACE_VIEW3D;
sa->type = BKE_spacetype_from_id(sa->spacetype);
}
@@ -1455,14 +1458,13 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
ar->type = BKE_regiontype_from_id_or_first(sa->type, ar->regiontype);
/* area sizes */
- 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_calc_totrct(sa, &window_rect);
/* region rect sizes */
rect = sa->totrct;
- region_rect_recursive(win, sa, sa->regionbase.first, &rect, 0);
+ overlap_rect = rect;
+ region_rect_recursive(win, sa, sa->regionbase.first, &rect, &overlap_rect, 0);
+ sa->flag &= ~AREA_FLAG_REGION_SIZE_UPDATE;
/* default area handlers */
ed_default_handlers(wm, sa, &sa->handlers, sa->type->keymapflag);
@@ -1470,22 +1472,31 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
if (sa->type->init)
sa->type->init(wm, sa);
+ /* clear all azones, add the area triange widgets */
+ area_azone_initialize(win, screen, 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 */
UI_blocklist_free(NULL, &ar->uiblocks);
}
+
+ /* Some AZones use View2D data which is only updated in region init, so call that first! */
+ region_azones_add(screen, sa, ar, ar->alignment & ~RGN_SPLIT_PREV);
}
+
+ WM_toolsystem_refresh_screen_area(workspace, scene, sa);
}
static void region_update_rect(ARegion *ar)
@@ -1500,22 +1511,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(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(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);
}
@@ -1526,10 +1531,25 @@ void ED_region_cursor_set(wmWindow *win, ScrArea *sa, ARegion *ar)
ar->type->cursor(win, sa, ar);
}
else {
+ if (WM_cursor_set_from_tool(win, sa, ar)) {
+ return;
+ }
WM_cursor_set(win, CURSOR_STD);
}
}
+/* for use after changing visiblity of regions */
+void ED_region_visibility_change_update(bContext *C, ARegion *ar)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (ar->flag & RGN_FLAG_HIDDEN)
+ WM_event_remove_handlers(C, &ar->handlers);
+
+ ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
+ ED_area_tag_redraw(sa);
+}
+
/* for quick toggle, can skip fades */
void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
{
@@ -1542,11 +1562,7 @@ void region_toggle_hidden(bContext *C, ARegion *ar, const bool do_fade)
region_blend_start(C, sa, ar);
}
else {
- if (ar->flag & RGN_FLAG_HIDDEN)
- WM_event_remove_handlers(C, &ar->handlers);
-
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
- ED_area_tag_redraw(sa);
+ ED_region_visibility_change_update(C, ar);
}
}
@@ -1566,10 +1582,8 @@ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
const char spacetype = sa_dst->spacetype;
const short flag_copy = HEADER_NO_PULLDOWN;
- sa_dst->headertype = sa_src->headertype;
sa_dst->spacetype = sa_src->spacetype;
sa_dst->type = sa_src->type;
- sa_dst->butspacetype = sa_src->butspacetype;
sa_dst->flag = (sa_dst->flag & ~flag_copy) | (sa_src->flag & flag_copy);
@@ -1597,10 +1611,8 @@ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
void ED_area_data_swap(ScrArea *sa_dst, ScrArea *sa_src)
{
- SWAP(short, sa_dst->headertype, sa_src->headertype);
SWAP(char, sa_dst->spacetype, sa_src->spacetype);
SWAP(SpaceType *, sa_dst->type, sa_src->type);
- SWAP(char, sa_dst->butspacetype, sa_src->butspacetype);
SWAP(ListBase, sa_dst->spacedata, sa_src->spacedata);
@@ -1639,12 +1651,15 @@ void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
*/
void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exit)
{
+ wmWindow *win = CTX_wm_window(C);
+
if (sa->spacetype != type) {
SpaceType *st;
SpaceLink *slold;
SpaceLink *sl;
/* store sa->type->exit callback */
void *sa_exit = sa->type ? sa->type->exit : NULL;
+ int header_alignment = ED_area_header_alignment(sa);
/* in some cases (opening temp space) we don't want to
* call area exit callback, so we temporarily unset it */
@@ -1663,9 +1678,12 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
slold = sa->spacedata.first;
sa->spacetype = type;
- sa->butspacetype = type;
sa->type = st;
+ /* If st->new may be called, don't use context until then. The
+ * sa->type->context() callback has changed but data may be invalid
+ * (e.g. with properties editor) until space-data is properly created */
+
/* check previously stored space */
for (sl = sa->spacedata.first; sl; sl = sl->next)
if (sl->spacetype == type)
@@ -1690,11 +1708,22 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
/* put in front of list */
BLI_remlink(&sa->spacedata, sl);
BLI_addhead(&sa->spacedata, sl);
+
+
+ /* Sync header alignment. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ ar->alignment = header_alignment;
+ break;
+ }
+ }
}
else {
/* new space */
if (st) {
- sl = st->new(C);
+ /* Don't get scene from context here which may depend on space-data. */
+ Scene *scene = WM_window_get_active_scene(win);
+ sl = st->new(sa, scene);
BLI_addhead(&sa->spacedata, sl);
/* swap regions */
@@ -1705,7 +1734,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
}
- ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
+ ED_area_initialize(CTX_wm_manager(C), win, sa);
/* tell WM to refresh, cursor types etc */
WM_event_add_mousemove(C);
@@ -1755,32 +1784,184 @@ int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
uiDefButR(block, UI_BTYPE_MENU, 0, "", xco, yco, 1.6 * U.widget_unit, U.widget_unit,
- &areaptr, "type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
+ &areaptr, "ui_type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
return xco + 1.7 * U.widget_unit;
}
/************************ standard UI regions ************************/
-void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int contextnr, const bool vertical)
+static ThemeColorID region_background_color_id(const bContext *C, const ARegion *region)
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ switch (region->regiontype) {
+ case RGN_TYPE_HEADER:
+ if (ED_screen_area_active(C) || ED_area_is_global(area)) {
+ return TH_HEADER;
+ }
+ else {
+ return TH_HEADERDESEL;
+ }
+ case RGN_TYPE_PREVIEW:
+ return TH_PREVIEW_BACK;
+ default:
+ return TH_BACK;
+ }
+}
+
+static void region_clear_color(const bContext *C, const ARegion *ar, ThemeColorID colorid)
+{
+ if (ar->alignment == RGN_ALIGN_FLOAT) {
+ /* handle our own drawing. */
+ }
+ else if (ar->overlap) {
+ /* view should be in pixelspace */
+ UI_view2d_view_restore(C);
+
+ float back[4];
+ UI_GetThemeColor4fv(colorid, back);
+ glClearColor(back[3] * back[0], back[3] * back[1], back[3] * back[2], back[3]);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+ else {
+ UI_ThemeClearColor(colorid);
+ glClear(GL_COLOR_BUFFER_BIT);
+ }
+}
+
+BLI_INLINE bool streq_array_any(const char *s, const char *arr[])
+{
+ for (uint i = 0; arr[i]; i++) {
+ if (STREQ(arr[i], s)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void ed_panel_draw(
+ const bContext *C,
+ ScrArea *sa,
+ ARegion *ar,
+ ListBase *lb,
+ PanelType *pt,
+ Panel *panel,
+ int w,
+ int em,
+ bool vertical)
{
- ScrArea *sa = CTX_wm_area(C);
uiStyle *style = UI_style_get_dpi();
- uiBlock *block;
+
+ /* draw panel */
+ uiBlock *block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
+
+ bool open;
+ panel = UI_panel_begin(sa, ar, lb, block, pt, panel, &open);
+
+ /* bad fixed values */
+ int xco, yco, h = 0;
+
+ if (pt->draw_header_preset && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ /* for preset menu */
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ 0, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+
+ pt->draw_header_preset(C, panel);
+
+ int headerend = w - UI_UNIT_X;
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ UI_block_translate(block, headerend - xco, 0);
+ panel->layout = NULL;
+ }
+
+ if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ int labelx, labely;
+ UI_panel_label_offset(block, &labelx, &labely);
+
+ /* for enabled buttons */
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ labelx, labely, UI_UNIT_Y, 1, 0, style);
+
+ pt->draw_header(C, panel);
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ panel->labelofs = xco - labelx;
+ panel->layout = NULL;
+ }
+ else {
+ panel->labelofs = 0;
+ }
+
+ if (open) {
+ short panelContext;
+
+ /* panel context can either be toolbar region or normal panels region */
+ if (ar->regiontype == RGN_TYPE_TOOLS)
+ panelContext = UI_LAYOUT_TOOLBAR;
+ else
+ panelContext = UI_LAYOUT_PANEL;
+
+ panel->layout = UI_block_layout(
+ block, UI_LAYOUT_VERTICAL, panelContext,
+ style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
+
+ pt->draw(C, panel);
+
+ UI_block_layout_resolve(block, &xco, &yco);
+ panel->layout = NULL;
+
+ if (yco != 0) {
+ h = -yco + 2 * style->panelspace;
+ }
+ }
+
+ UI_block_end(C, block);
+
+ /* Draw child panels. */
+ if (open) {
+ for (LinkData *link = pt->children.first; link; link = link->next) {
+ PanelType *child_pt = link->data;
+ Panel *child_panel = UI_panel_find_by_type(&panel->children, child_pt);
+
+ if (child_pt->draw && (!child_pt->poll || child_pt->poll(C, child_pt))) {
+ ed_panel_draw(C, sa, ar, &panel->children, child_pt, child_panel, w, em, vertical);
+ }
+ }
+ }
+
+ UI_panel_end(block, w, h);
+}
+
+/**
+ * \param contexts: A NULL terminated array of context strings to match against.
+ * Matching against any of these strings will draw the panel.
+ * Can be NULL to skip context checks.
+ */
+void ED_region_panels_layout_ex(
+ const bContext *C, ARegion *ar,
+ const char *contexts[], int contextnr, const bool vertical)
+{
+ ar->runtime.category = NULL;
+
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ ScrArea *sa = CTX_wm_area(C);
PanelType *pt;
- Panel *panel;
View2D *v2d = &ar->v2d;
- View2DScrollers *scrollers;
- int x, y, xco, yco, w, em, triangle;
+ int x, y, w, em;
bool is_context_new = 0;
- int redo;
int scroll;
- bool use_category_tabs = (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI)); /* XXX, should use some better check? */
+ /* XXX, should use some better check? */
+ bool use_category_tabs = (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI));
/* offset panels for small vertical tab area */
const char *category = NULL;
const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
int margin_x = 0;
+ const bool region_layout_based = ar->flag & RGN_FLAG_DYNAMIC_SIZE;
BLI_SMALLSTACK_DECLARE(pt_stack, PanelType *);
@@ -1809,8 +1990,18 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
/* collect panels to draw */
for (pt = ar->type->paneltypes.last; pt; pt = pt->prev) {
+ /* Only draw top level panels. */
+ if (pt->parent) {
+ continue;
+ }
+
/* verify context */
- if (context && pt->context[0] && !STREQ(context, pt->context)) {
+ if (contexts && pt->context[0] && !streq_array_any(pt->context, contexts)) {
+ continue;
+ }
+
+ /* If we're tagged, only use compatible. */
+ if (pt->owner_id[0] && BKE_workspace_owner_id_check(workspace, pt->owner_id) == false) {
continue;
}
@@ -1846,154 +2037,118 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
}
- /* sortof hack - but we cannot predict the height of panels, until it's being generated */
- /* the layout engine works with fixed width (from v2d->cur), which is being set at end of the loop */
- /* in case scroller settings (hide flags) differ from previous, the whole loop gets done again */
- for (redo = 2; redo > 0; redo--) {
-
- if (vertical) {
- w = BLI_rctf_size_x(&v2d->cur);
- em = (ar->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */
- }
- else {
- w = UI_PANEL_WIDTH;
- em = (ar->type->prefsizex) ? 10 : 20;
- }
-
- w -= margin_x;
+ if (vertical) {
+ w = BLI_rctf_size_x(&v2d->cur);
+ em = (ar->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */
+ }
+ else {
+ w = UI_PANEL_WIDTH;
+ em = (ar->type->prefsizex) ? 10 : 20;
+ }
- /* create panels */
- UI_panels_begin(C, ar);
+ w -= margin_x;
- /* set view2d view matrix - UI_block_begin() stores it */
- UI_view2d_view_ortho(v2d);
+ /* create panels */
+ UI_panels_begin(C, ar);
- BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
- {
- bool open;
+ /* set view2d view matrix - UI_block_begin() stores it */
+ UI_view2d_view_ortho(v2d);
- panel = UI_panel_find_by_type(ar, pt);
+ BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
+ {
+ Panel *panel = UI_panel_find_by_type(&ar->panels, pt);
- if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
- if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
- continue;
- }
+ if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
+ if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
+ continue;
}
+ }
- /* draw panel */
- block = UI_block_begin(C, ar, pt->idname, UI_EMBOSS);
- panel = UI_panel_begin(sa, ar, block, pt, panel, &open);
-
- /* bad fixed values */
- triangle = (int)(UI_UNIT_Y * 1.1f);
-
- if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
- /* for enabled buttons */
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
- triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, 0, style);
+ ed_panel_draw(C, sa, ar, &ar->panels, pt, panel, w, em, vertical);
+ }
+ BLI_SMALLSTACK_ITER_END;
- pt->draw_header(C, panel);
+ /* align panels and return size */
+ UI_panels_end(C, ar, &x, &y);
- UI_block_layout_resolve(block, &xco, &yco);
- panel->labelofs = xco - triangle;
- panel->layout = NULL;
- }
- else {
- panel->labelofs = 0;
+ /* before setting the view */
+ if (region_layout_based) {
+ /* XXX, only single panel support atm.
+ * Can't use x/y values calculated above because they're not using the real height of panels,
+ * instead they calculate offsets for the next panel to start drawing. */
+ Panel *panel = ar->panels.last;
+ if (panel != NULL) {
+ int size_dyn[2] = {
+ UI_UNIT_X * ((panel->flag & PNL_CLOSED) ? 8 : 14),
+ UI_panel_size_y(panel),
+ };
+ /* region size is layout based and needs to be updated */
+ if ((ar->sizex != size_dyn[0]) ||
+ (ar->sizey != size_dyn[1]))
+ {
+ ar->sizex = size_dyn[0];
+ ar->sizey = size_dyn[1];
+ sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
}
-
- if (open) {
- short panelContext;
-
- /* panel context can either be toolbar region or normal panels region */
- if (ar->regiontype == RGN_TYPE_TOOLS)
- panelContext = UI_LAYOUT_TOOLBAR;
- else
- panelContext = UI_LAYOUT_PANEL;
-
- panel->layout = UI_block_layout(
- block, UI_LAYOUT_VERTICAL, panelContext,
- style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
-
- pt->draw(C, panel);
-
- UI_block_layout_resolve(block, &xco, &yco);
- panel->layout = NULL;
-
- yco -= 2 * style->panelspace;
- UI_panel_end(block, w, -yco);
+ y = ABS(ar->sizey - 1);
+ }
+ }
+ else if (vertical) {
+ /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */
+ if (v2d->cur.ymax < -FLT_EPSILON) {
+ /* Clamp to lower view boundary */
+ if (v2d->tot.ymin < -v2d->winy) {
+ y = min_ii(y, 0);
}
else {
- yco = 0;
- UI_panel_end(block, w, 0);
+ y = min_ii(y, v2d->cur.ymin);
}
-
- UI_block_end(C, block);
}
- BLI_SMALLSTACK_ITER_END;
-
- /* align panels and return size */
- UI_panels_end(C, ar, &x, &y);
- /* before setting the view */
- if (vertical) {
- /* we always keep the scroll offset - so the total view gets increased with the scrolled away part */
- if (v2d->cur.ymax < -FLT_EPSILON) {
- /* Clamp to lower view boundary */
- if (v2d->tot.ymin < -v2d->winy) {
- y = min_ii(y, 0);
- }
- else {
- y = min_ii(y, v2d->cur.ymin);
- }
+ y = -y;
+ }
+ else {
+ /* don't jump back when panels close or hide */
+ if (!is_context_new) {
+ if (v2d->tot.xmax > v2d->winx) {
+ x = max_ii(x, 0);
}
-
- y = -y;
- }
- else {
- /* don't jump back when panels close or hide */
- if (!is_context_new) {
- if (v2d->tot.xmax > v2d->winx) {
- x = max_ii(x, 0);
- }
- else {
- x = max_ii(x, v2d->cur.xmax);
- }
+ else {
+ x = max_ii(x, v2d->cur.xmax);
}
-
- y = -y;
}
- /* this also changes the 'cur' */
- UI_view2d_totRect_set(v2d, x, y);
+ y = -y;
+ }
+
+ /* this also changes the 'cur' */
+ UI_view2d_totRect_set(v2d, x, y);
- if (scroll != v2d->scroll) {
- /* Note: this code scales fine, but because of rounding differences, positions of elements
- * flip +1 or -1 pixel compared to redoing the entire layout again.
- * Leaving in commented code for future tests */
+ if (scroll != v2d->scroll) {
+ /* Note: this code scales fine, but because of rounding differences, positions of elements
+ * flip +1 or -1 pixel compared to redoing the entire layout again.
+ * Leaving in commented code for future tests */
#if 0
- UI_panels_scale(ar, BLI_rctf_size_x(&v2d->cur));
- break;
+ UI_panels_scale(ar, BLI_rctf_size_x(&v2d->cur));
+ break;
#endif
- }
- else {
- break;
- }
}
- /* clear */
- if (ar->overlap) {
- /* 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);
- glDisable(GL_BLEND);
+ if (use_category_tabs) {
+ ar->runtime.category = category;
}
- else {
- UI_ThemeClearColor((ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
- glClear(GL_COLOR_BUFFER_BIT);
+}
+void ED_region_panels_layout(const bContext *C, ARegion *ar)
+{
+ ED_region_panels_layout_ex(C, ar, NULL, -1, true);
+}
+
+void ED_region_panels_draw(const bContext *C, ARegion *ar)
+{
+ View2D *v2d = &ar->v2d;
+
+ if (ar->alignment != RGN_ALIGN_FLOAT) {
+ region_clear_color(C, ar, (ar->type->regionid == RGN_TYPE_PREVIEW) ? TH_PREVIEW_BACK : TH_BACK);
}
/* reset line width for drawing tabs */
@@ -2008,16 +2163,34 @@ void ED_region_panels(const bContext *C, ARegion *ar, const char *context, int c
/* restore view matrix */
UI_view2d_view_restore(C);
- if (use_category_tabs) {
- UI_panel_category_draw_all(ar, category);
+ /* Set in layout. */
+ if (ar->runtime.category) {
+ UI_panel_category_draw_all(ar, ar->runtime.category);
}
/* scrollers */
- scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
+ View2DScrollers *scrollers = UI_view2d_scrollers_calc(
+ C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
UI_view2d_scrollers_free(scrollers);
}
+void ED_region_panels_ex(
+ const bContext *C, ARegion *ar,
+ const char *contexts[], int contextnr, const bool vertical)
+{
+ /* TODO: remove? */
+ ED_region_panels_layout_ex(C, ar, contexts, contextnr, vertical);
+ ED_region_panels_draw(C, ar);
+}
+
+void ED_region_panels(const bContext *C, ARegion *ar)
+{
+ /* TODO: remove? */
+ ED_region_panels_layout(C, ar);
+ ED_region_panels_draw(C, ar);
+}
+
void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
@@ -2028,7 +2201,7 @@ void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler(&ar->handlers, keymap);
}
-void ED_region_header(const bContext *C, ARegion *ar)
+void ED_region_header_layout(const bContext *C, ARegion *ar)
{
uiStyle *style = UI_style_get_dpi();
uiBlock *block;
@@ -2037,16 +2210,19 @@ void ED_region_header(const bContext *C, ARegion *ar)
Header header = {NULL};
int maxco, xco, yco;
int headery = ED_area_headersize();
-
- /* clear */
- UI_ThemeClearColor((ED_screen_area_active(C)) ? TH_HEADER : TH_HEADERDESEL);
- glClear(GL_COLOR_BUFFER_BIT);
+ bool region_layout_based = ar->flag & RGN_FLAG_DYNAMIC_SIZE;
/* set view2d view matrix for scrolling (without scrollers) */
UI_view2d_view_ortho(&ar->v2d);
- xco = maxco = 0.4f * UI_UNIT_X;
- yco = headery - floor(0.2f * UI_UNIT_Y);
+ xco = maxco = UI_HEADER_OFFSET;
+ yco = headery + (ar->winy - headery) / 2 - floor(0.2f * UI_UNIT_Y);
+
+ /* XXX workaround for 1 px alignment issue. Not sure what causes it... Would prefer a proper fix - Julian */
+ if (CTX_wm_area(C)->spacetype == SPACE_TOPBAR) {
+ xco += 1;
+ yco += 1;
+ }
/* draw all headers types */
for (ht = ar->type->headertypes.first; ht; ht = ht->next) {
@@ -2070,17 +2246,54 @@ void ED_region_header(const bContext *C, ARegion *ar)
if (xco > maxco)
maxco = xco;
+ int new_sizex = (maxco + UI_HEADER_OFFSET) / UI_DPI_FAC;
+
+ if (region_layout_based && (ar->sizex != new_sizex)) {
+ /* region size is layout based and needs to be updated */
+ ScrArea *sa = CTX_wm_area(C);
+
+ ar->sizex = new_sizex;
+ sa->flag |= AREA_FLAG_REGION_SIZE_UPDATE;
+ }
+
UI_block_end(C, block);
- UI_block_draw(C, block);
+ }
+
+ if (!region_layout_based) {
+ maxco += UI_HEADER_OFFSET;
}
/* always as last */
- UI_view2d_totRect_set(&ar->v2d, maxco + UI_UNIT_X + 80, headery);
+ UI_view2d_totRect_set(&ar->v2d, maxco, headery);
+
+ /* restore view matrix */
+ UI_view2d_view_restore(C);
+}
+
+void ED_region_header_draw(const bContext *C, ARegion *ar)
+{
+ /* clear */
+ region_clear_color(C, ar, region_background_color_id(C, ar));
- /* restore view matrix? */
+ UI_view2d_view_ortho(&ar->v2d);
+
+ /* View2D matrix might have changed due to dynamic sized regions. */
+ UI_blocklist_update_window_matrix(C, &ar->uiblocks);
+
+ /* draw blocks */
+ UI_blocklist_draw(C, &ar->uiblocks);
+
+ /* restore view matrix */
UI_view2d_view_restore(C);
}
+void ED_region_header(const bContext *C, ARegion *ar)
+{
+ /* TODO: remove? */
+ ED_region_header_layout(C, ar);
+ ED_region_header_draw(C, ar);
+}
+
void ED_region_header_init(ARegion *ar)
{
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
@@ -2092,42 +2305,132 @@ 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)
+
+int ED_area_header_alignment(const ScrArea *area)
+{
+ for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ return ar->alignment;
+ }
+ }
+
+ return RGN_ALIGN_TOP;
+}
+
+/**
+ * \return the final height of a global \a area, accounting for DPI.
+ */
+int ED_area_global_size_y(const ScrArea *area)
+{
+ BLI_assert(ED_area_is_global(area));
+ return round_fl_to_int(area->global->cur_fixed_height * UI_DPI_FAC);
+}
+
+bool ED_area_is_global(const ScrArea *area)
+{
+ return area->global != NULL;
+}
+
+ScrArea *ED_screen_areas_iter_first(const wmWindow *win, const bScreen *screen)
+{
+ ScrArea *global_area = win->global_areas.areabase.first;
+
+ if (!global_area) {
+ return screen->areabase.first;
+ }
+ else if ((global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
+ return global_area;
+ }
+ /* Find next visible area. */
+ return ED_screen_areas_iter_next(screen, global_area);
+}
+ScrArea *ED_screen_areas_iter_next(const bScreen *screen, const ScrArea *area)
+{
+ if (area->global) {
+ for (ScrArea *area_iter = area->next; area_iter; area_iter = area_iter->next) {
+ if ((area_iter->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
+ return area_iter;
+ }
+ }
+ /* No visible next global area found, start iterating over layout areas. */
+ return screen->areabase.first;
+ }
+
+ return area->next;
+}
+
+/**
+ * For now we just assume all global areas are made up out of horizontal bars
+ * with the same size. A fixed size could be stored in ARegion instead if needed.
+ *
+ * \return the DPI aware height of a single bar/region in global areas.
+ */
+int ED_region_global_size_y(void)
+{
+ return ED_area_headersize(); /* same size as header */
+}
+
+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.ymax = BLI_rcti_size_y(&ar->winrct);
+ rect.ymin = rect.ymax - header_height * num_lines;
/* setup scissor */
glGetIntegerv(GL_SCISSOR_BOX, scissor);
- glScissor(ar->winrct.xmin + rect.xmin, ar->winrct.ymin + rect.ymin,
+ glScissor(rect.xmin, rect.ymin,
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 +2438,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 +2611,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 +2625,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 +2650,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 +2679,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 +2708,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 */
@@ -2434,14 +2778,32 @@ void ED_region_visible_rect(ARegion *ar, rcti *rect)
for (; arn; arn = arn->next) {
if (ar != arn && arn->overlap) {
if (BLI_rcti_isect(rect, &arn->winrct, NULL)) {
+ if (ELEM(arn->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
+ /* Overlap left, also check 1 pixel offset (2 regions on one side). */
+ if (ABS(rect->xmin - arn->winrct.xmin) < 2) {
+ rect->xmin = arn->winrct.xmax;
+ }
- /* overlap left, also check 1 pixel offset (2 regions on one side) */
- if (ABS(rect->xmin - arn->winrct.xmin) < 2)
- rect->xmin = arn->winrct.xmax;
-
- /* overlap right */
- if (ABS(rect->xmax - arn->winrct.xmax) < 2)
- rect->xmax = arn->winrct.xmin;
+ /* Overlap right. */
+ if (ABS(rect->xmax - arn->winrct.xmax) < 2) {
+ rect->xmax = arn->winrct.xmin;
+ }
+ }
+ else if (ELEM(arn->alignment, RGN_ALIGN_TOP, RGN_ALIGN_BOTTOM)) {
+ /* Same logic as above for vertical regions. */
+ if (ABS(rect->ymin - arn->winrct.ymin) < 2) {
+ rect->ymin = arn->winrct.ymax;
+ }
+ if (ABS(rect->ymax - arn->winrct.ymax) < 2) {
+ rect->ymax = arn->winrct.ymin;
+ }
+ }
+ else if (arn->alignment == RGN_ALIGN_FLOAT) {
+ /* Skip floating. */
+ }
+ else {
+ BLI_assert(!"Region overlap with unknown alignment");
+ }
}
}
}
@@ -2452,8 +2814,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 +2834,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 +2848,73 @@ 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);
+ }
+}
+
+int ED_region_snap_size_test(const ARegion *ar)
+{
+ /* Use a larger value because toggling scrollbars can jump in size. */
+ const int snap_match_threshold = 16;
+ if (ar->type->snap_size != NULL) {
+ return ((((ar->sizex - ar->type->snap_size(ar, ar->sizex, 0)) <= snap_match_threshold) << 0) |
+ (((ar->sizey - ar->type->snap_size(ar, ar->sizey, 1)) <= snap_match_threshold) << 1));
+ }
+ return 0;
+}
+
+bool ED_region_snap_size_apply(ARegion *ar, int snap_flag)
+{
+ bool changed = false;
+ if (ar->type->snap_size != NULL) {
+ if (snap_flag & (1 << 0)) {
+ short snap_size = ar->type->snap_size(ar, ar->sizex, 0);
+ if (snap_size != ar->sizex) {
+ ar->sizex = snap_size;
+ changed = true;
+ }
+ }
+ if (snap_flag & (1 << 1)) {
+ short snap_size = ar->type->snap_size(ar, ar->sizey, 1);
+ if (snap_size != ar->sizey) {
+ ar->sizey = snap_size;
+ changed = true;
+ }
}
}
+ return changed;
}
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 6e9a580e403..1d73566e5a8 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,12 +206,6 @@ 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;
@@ -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");
@@ -429,20 +228,23 @@ void glaDrawPixelsTexScaled_clipping(float x, float y, int img_w, int img_h,
if (type == GL_FLOAT) {
/* need to set internal format to higher range float */
-
- /* NOTE: this could fail on some drivers, like mesa,
- * but currently this code is only used by color
- * management stuff which already checks on whether
- * it's possible to use GL_RGBA16F_ARB
- */
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F_ARB, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
}
else {
/* switch to 8bit RGBA for byte buffer */
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;
@@ -494,325 +296,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();
}
}
- glBindTexture(GL_TEXTURE_2D, 0);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ if (state->do_shader_unbind) {
+ immUnbindProgram();
+ }
-#if defined(__APPLE__) && 0
- /* workaround for os x 10.5/10.6 driver bug (above) */
- glPixelZoom(xzoom, yzoom);
-#endif
+ glBindTexture(GL_TEXTURE_2D, 0);
+ 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)
-{
- 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)
+ float clip_min_x, float clip_min_y, float clip_max_x, float clip_max_y,
+ float xzoom, float yzoom, float color[4])
{
- 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 +363,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 +394,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 +410,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 +430,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 +453,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 +464,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 +494,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 +508,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 +520,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 +529,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 +550,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 b90430f27e2..864150be9da 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "DNA_object_types.h"
#include "DNA_armature_types.h"
#include "DNA_gpencil_types.h"
@@ -38,17 +40,21 @@
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BLI_utildefines.h"
-
#include "BKE_context.h"
#include "BKE_object.h"
#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 +67,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 +87,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 +104,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);
}
}
}
@@ -206,38 +210,47 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
const bool editable_bones = CTX_data_equals(member, "editable_bones");
if (arm && arm->edbo) {
- /* Attention: X-Axis Mirroring is also handled here... */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_VISIBLE(arm, ebone)) {
- /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
- * so that most users of this data don't need to explicitly check for it themselves.
- *
- * We need to make sure that these mirrored copies are not selected, otherwise some
- * bones will be operated on twice.
- */
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
-
- /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
- if (editable_bones) {
- /* only selected + editable */
- if (EBONE_EDITABLE(ebone)) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ arm = ob->data;
+
+ /* Attention: X-Axis Mirroring is also handled here... */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_VISIBLE(arm, ebone)) {
+ /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
+ * so that most users of this data don't need to explicitly check for it themselves.
+ *
+ * We need to make sure that these mirrored copies are not selected, otherwise some
+ * bones will be operated on twice.
+ */
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+
+ /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
+ if (editable_bones) {
+ /* only selected + editable */
+ if (EBONE_EDITABLE(ebone)) {
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
+
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
+ }
+ }
+ else {
+ /* only include bones if visible */
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
- if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
+ if ((flipbone) && EBONE_VISIBLE(arm, flipbone) == 0)
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
- else {
- /* only include bones if visible */
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
-
- if ((flipbone) && EBONE_VISIBLE(arm, flipbone) == 0)
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
- }
}
}
+ MEM_freeN(objects);
+
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
@@ -248,53 +261,65 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
const bool selected_editable_bones = CTX_data_equals(member, "selected_editable_bones");
if (arm && arm->edbo) {
- /* Attention: X-Axis Mirroring is also handled here... */
- for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
- /* first and foremost, bone must be visible and selected */
- if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_SELECTED)) {
- /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
- * so that most users of this data don't need to explicitly check for it themselves.
- *
- * We need to make sure that these mirrored copies are not selected, otherwise some
- * bones will be operated on twice.
- */
- if (arm->flag & ARM_MIRROR_EDIT)
- flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
-
- /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
- if (selected_editable_bones) {
- /* only selected + editable */
- if (EBONE_EDITABLE(ebone)) {
+ uint objects_len;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, &objects_len);
+ for (uint i = 0; i < objects_len; i++) {
+ Object *ob = objects[i];
+ arm = ob->data;
+
+ /* Attention: X-Axis Mirroring is also handled here... */
+ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
+ /* first and foremost, bone must be visible and selected */
+ if (EBONE_VISIBLE(arm, ebone) && (ebone->flag & BONE_SELECTED)) {
+ /* Get 'x-axis mirror equivalent' bone if the X-Axis Mirroring option is enabled
+ * so that most users of this data don't need to explicitly check for it themselves.
+ *
+ * We need to make sure that these mirrored copies are not selected, otherwise some
+ * bones will be operated on twice.
+ */
+ if (arm->flag & ARM_MIRROR_EDIT)
+ flipbone = ED_armature_ebone_get_mirrored(arm->edbo, ebone);
+
+ /* if we're filtering for editable too, use the check for that instead, as it has selection check too */
+ if (selected_editable_bones) {
+ /* only selected + editable */
+ if (EBONE_EDITABLE(ebone)) {
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
+
+ if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
+ CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
+ }
+ }
+ else {
+ /* only include bones if selected */
CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
}
}
- else {
- /* only include bones if selected */
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, ebone);
-
- if ((flipbone) && !(flipbone->flag & BONE_SELECTED))
- CTX_data_list_add(result, &arm->id, &RNA_EditBone, flipbone);
- }
}
}
+ MEM_freeN(objects);
+
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
}
}
else if (CTX_data_equals(member, "visible_pose_bones")) {
Object *obpose = BKE_object_pose_armature_get(obact);
- bArmature *arm = (obpose) ? obpose->data : NULL;
- bPoseChannel *pchan;
-
- if (obpose && obpose->pose && arm) {
- for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
- if (PBONE_VISIBLE(arm, pchan->bone)) {
+ if (obpose && obpose->pose && obpose->data) {
+ if (obpose != obact) {
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (obpose, pchan) {
CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
- }
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) {
+ FOREACH_PCHAN_VISIBLE_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_VISIBLE_IN_OBJECT_END;
+ } FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
@@ -302,16 +327,18 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
}
else if (CTX_data_equals(member, "selected_pose_bones")) {
Object *obpose = BKE_object_pose_armature_get(obact);
- bArmature *arm = (obpose) ? obpose->data : NULL;
- bPoseChannel *pchan;
-
- if (obpose && obpose->pose && arm) {
- for (pchan = obpose->pose->chanbase.first; pchan; pchan = pchan->next) {
- /* ensure that PoseChannel is on visible layer and is not hidden in PoseMode */
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
- CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
- }
+ if (obpose && obpose->pose && obpose->data) {
+ if (obpose != obact) {
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (obpose, pchan) {
+ CTX_data_list_add(result, &obpose->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ }
+ else if (obact->mode & OB_MODE_POSE) {
+ FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, OB_MODE_POSE, ob_iter) {
+ FOREACH_PCHAN_SELECTED_IN_OBJECT_BEGIN (ob_iter, pchan) {
+ CTX_data_list_add(result, &ob_iter->id, &RNA_PoseBone, pchan);
+ } FOREACH_PCHAN_SELECTED_IN_OBJECT_END;
+ } FOREACH_OBJECT_IN_MODE_END;
}
CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION);
return 1;
@@ -345,8 +372,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 12f45faee94..fec39ade110 100644
--- a/source/blender/editors/screen/screen_draw.c
+++ b/source/blender/editors/screen/screen_draw.c
@@ -22,18 +22,26 @@
* \ingroup edscr
*/
-#include "BIF_gl.h"
+#include "ED_screen.h"
+
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+
+#include "BLI_math.h"
#include "WM_api.h"
+#include "WM_types.h"
-#include "ED_screen.h"
+#include "UI_interface.h"
+#include "UI_resources.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 +98,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;
@@ -164,93 +179,252 @@ 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, pos);
+ }
+}
+
+#define CORNER_RESOLUTION 10
+static void drawscredge_corner_geometry(
+ int sizex, int sizey,
+ int corner_x, int corner_y,
+ int center_x, int center_y,
+ double angle_offset,
+ const float *color)
+{
+ const int radius = ABS(corner_x - center_x);
+ const int line_thickness = U.pixelsize;
+
+ if (corner_x < center_x) {
+ if (corner_x > 0.0f) {
+ /* Left (internal) edge. */
+ corner_x += line_thickness;
+ center_x += line_thickness;
+ }
}
else {
- draw_horizontal_join_shape(sa, dir);
+ /* Right (internal) edge. */
+ if (corner_x < sizex - 1) {
+ corner_x += 1 - line_thickness;
+ center_x += 1 - line_thickness;
+ }
+ else {
+ /* Corner case, extreme right edge. */
+ corner_x += 1;
+ center_x += 1;
+ }
+ }
+
+ if (corner_y < center_y) {
+ if (corner_y > 0.0f) {
+ /* Bottom (internal) edge. */
+ corner_y += line_thickness;
+ center_y += line_thickness;
+ }
+ }
+ else {
+ /* Top (internal) edge. */
+ if (corner_y < sizey) {
+ corner_y += 1 - line_thickness;
+ center_y += 1 - line_thickness;
+ }
}
+
+ float tri_array[CORNER_RESOLUTION + 1][2];
+
+ tri_array[0][0] = corner_x;
+ tri_array[0][1] = corner_y;
+
+ for (int i = 0; i < CORNER_RESOLUTION; i++) {
+ double angle = angle_offset + (M_PI_2 * ((float)i / (CORNER_RESOLUTION - 1)));
+ float x = center_x + (radius * cos(angle));
+ float y = center_y + (radius * sin(angle));
+ tri_array[i + 1][0] = x;
+ tri_array[i + 1][1] = y;
+ }
+
+ UI_draw_anti_fan(tri_array, CORNER_RESOLUTION + 1, color);
+}
+
+#undef CORNER_RESOLUTION
+
+static void drawscredge_corner(ScrArea *sa, int sizex, int sizey)
+{
+ int size = 10 * U.pixelsize;
+ float color[4] = {0};
+ UI_GetThemeColor4fv(TH_EDITOR_OUTLINE, color);
+
+ /* Bottom-Left. */
+ drawscredge_corner_geometry(sizex, sizey,
+ sa->v1->vec.x,
+ sa->v1->vec.y,
+ sa->v1->vec.x + size,
+ sa->v1->vec.y + size,
+ M_PI_2 * 2.0f,
+ color);
+
+ /* Top-Left. */
+ drawscredge_corner_geometry(sizex, sizey,
+ sa->v2->vec.x,
+ sa->v2->vec.y,
+ sa->v2->vec.x + size,
+ sa->v2->vec.y - size,
+ M_PI_2,
+ color);
+
+ /* Top-Right. */
+ drawscredge_corner_geometry(sizex, sizey,
+ sa->v3->vec.x,
+ sa->v3->vec.y,
+ sa->v3->vec.x - size,
+ sa->v3->vec.y - size,
+ 0.0f,
+ color);
+
+ /* Bottom-Right. */
+ drawscredge_corner_geometry(sizex, sizey,
+ sa->v4->vec.x,
+ sa->v4->vec.y,
+ sa->v4->vec.x - size,
+ sa->v4->vec.y + size,
+ M_PI_2 * 3.0f,
+ color);
+
+ /* Wrap up the corners with a nice embossing. */
+ rcti rect = sa->totrct;
+
+ unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4fv(color);
+ immBeginAtMost(GWN_PRIM_LINES, 8);
+
+ /* Right. */
+ immVertex2f(pos, rect.xmax, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymin);
+
+ /* Bottom. */
+ immVertex2f(pos, rect.xmax, rect.ymin);
+ immVertex2f(pos, rect.xmin, rect.ymin);
+
+ /* Left. */
+ immVertex2f(pos, rect.xmin, rect.ymin);
+ immVertex2f(pos, rect.xmin, rect.ymax);
+
+ /* Top. */
+ immVertex2f(pos, rect.xmin, rect.ymax);
+ immVertex2f(pos, rect.xmax, rect.ymax);
+
+ immEnd();
+ immUnbindProgram();
}
/**
* 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 +432,40 @@ 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);
+ 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();
+ immUniformThemeColor(TH_EDITOR_OUTLINE);
+
+ 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);
+ immUniformThemeColor(TH_EDITOR_OUTLINE);
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_area(sa, winsize_x, winsize_y, pos);
+ }
+
+ immUnbindProgram();
+
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ drawscredge_corner(sa, winsize_x, winsize_y);
}
- glEnd();
- win->screen->do_draw = false;
+ screen->do_draw = false;
}
/**
@@ -295,6 +476,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 +503,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 82552c35786..53abe3ed4ea 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -33,7 +33,9 @@
#include "MEM_guardedalloc.h"
+#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_workspace_types.h"
#include "DNA_userdef_types.h"
#include "BLI_math.h"
@@ -41,18 +43,17 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
-
-#include "BIF_gl.h"
-#include "BIF_glutil.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -66,198 +67,43 @@
#include "UI_interface.h"
-/* XXX actually should be not here... solve later */
-#include "wm_subwindow.h"
+#include "WM_message.h"
+
+#include "DEG_depsgraph_query.h"
#include "screen_intern.h" /* own module include */
/* ******************* screen vert, edge, area managing *********************** */
-static ScrVert *screen_addvert(bScreen *sc, short x, short y)
+static ScrVert *screen_addvert_ex(ScrAreaMap *area_map, short x, short y)
{
ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert");
sv->vec.x = x;
sv->vec.y = y;
- BLI_addtail(&sc->vertbase, sv);
+ BLI_addtail(&area_map->vertbase, sv);
return sv;
}
-
-static void sortscrvert(ScrVert **v1, ScrVert **v2)
+static ScrVert *screen_addvert(bScreen *sc, short x, short y)
{
- ScrVert *tmp;
-
- if (*v1 > *v2) {
- tmp = *v1;
- *v1 = *v2;
- *v2 = tmp;
- }
+ return screen_addvert_ex(AREAMAP_FROM_SCREEN(sc), x, y);
}
-static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
+static ScrEdge *screen_addedge_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2)
{
ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge");
- sortscrvert(&v1, &v2);
+ BKE_screen_sort_scrvert(&v1, &v2);
se->v1 = v1;
se->v2 = v2;
- BLI_addtail(&sc->edgebase, se);
+ BLI_addtail(&area_map->edgebase, se);
return se;
}
-
-
-ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
-{
- ScrEdge *se;
-
- sortscrvert(&v1, &v2);
- for (se = sc->edgebase.first; se; se = se->next)
- if (se->v1 == v1 && se->v2 == v2)
- return se;
-
- return NULL;
-}
-
-void removedouble_scrverts(bScreen *sc)
-{
- ScrVert *v1, *verg;
- ScrEdge *se;
- ScrArea *sa;
-
- verg = sc->vertbase.first;
- while (verg) {
- if (verg->newv == NULL) { /* !!! */
- v1 = verg->next;
- while (v1) {
- if (v1->newv == NULL) { /* !?! */
- if (v1->vec.x == verg->vec.x && v1->vec.y == verg->vec.y) {
- /* printf("doublevert\n"); */
- v1->newv = verg;
- }
- }
- v1 = v1->next;
- }
- }
- verg = verg->next;
- }
-
- /* replace pointers in edges and faces */
- se = sc->edgebase.first;
- while (se) {
- if (se->v1->newv) se->v1 = se->v1->newv;
- if (se->v2->newv) se->v2 = se->v2->newv;
- /* edges changed: so.... */
- sortscrvert(&(se->v1), &(se->v2));
- se = se->next;
- }
- sa = sc->areabase.first;
- while (sa) {
- if (sa->v1->newv) sa->v1 = sa->v1->newv;
- if (sa->v2->newv) sa->v2 = sa->v2->newv;
- if (sa->v3->newv) sa->v3 = sa->v3->newv;
- if (sa->v4->newv) sa->v4 = sa->v4->newv;
- sa = sa->next;
- }
-
- /* remove */
- verg = sc->vertbase.first;
- while (verg) {
- v1 = verg->next;
- if (verg->newv) {
- BLI_remlink(&sc->vertbase, verg);
- MEM_freeN(verg);
- }
- verg = v1;
- }
-
-}
-
-void removenotused_scrverts(bScreen *sc)
-{
- ScrVert *sv, *svn;
- ScrEdge *se;
-
- /* we assume edges are ok */
-
- se = sc->edgebase.first;
- while (se) {
- se->v1->flag = 1;
- se->v2->flag = 1;
- se = se->next;
- }
-
- sv = sc->vertbase.first;
- while (sv) {
- svn = sv->next;
- if (sv->flag == 0) {
- BLI_remlink(&sc->vertbase, sv);
- MEM_freeN(sv);
- }
- else {
- sv->flag = 0;
- }
- sv = svn;
- }
-}
-
-void removedouble_scredges(bScreen *sc)
-{
- ScrEdge *verg, *se, *sn;
-
- /* compare */
- verg = sc->edgebase.first;
- while (verg) {
- se = verg->next;
- while (se) {
- sn = se->next;
- if (verg->v1 == se->v1 && verg->v2 == se->v2) {
- BLI_remlink(&sc->edgebase, se);
- MEM_freeN(se);
- }
- se = sn;
- }
- verg = verg->next;
- }
-}
-
-void removenotused_scredges(bScreen *sc)
+static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
{
- ScrEdge *se, *sen;
- ScrArea *sa;
- int a = 0;
-
- /* sets flags when edge is used in area */
- sa = sc->areabase.first;
- while (sa) {
- se = screen_findedge(sc, sa->v1, sa->v2);
- if (se == NULL) printf("error: area %d edge 1 doesn't exist\n", a);
- else se->flag = 1;
- se = screen_findedge(sc, sa->v2, sa->v3);
- if (se == NULL) printf("error: area %d edge 2 doesn't exist\n", a);
- else se->flag = 1;
- se = screen_findedge(sc, sa->v3, sa->v4);
- if (se == NULL) printf("error: area %d edge 3 doesn't exist\n", a);
- else se->flag = 1;
- se = screen_findedge(sc, sa->v4, sa->v1);
- if (se == NULL) printf("error: area %d edge 4 doesn't exist\n", a);
- else se->flag = 1;
- sa = sa->next;
- a++;
- }
- se = sc->edgebase.first;
- while (se) {
- sen = se->next;
- if (se->flag == 0) {
- BLI_remlink(&sc->edgebase, se);
- MEM_freeN(se);
- }
- else {
- se->flag = 0;
- }
- se = sen;
- }
+ return screen_addedge_ex(AREAMAP_FROM_SCREEN(sc), v1, v2);
}
bool scredge_is_horizontal(ScrEdge *se)
@@ -265,19 +111,21 @@ bool scredge_is_horizontal(ScrEdge *se)
return (se->v1->vec.y == se->v2->vec.y);
}
-/* need win size to make sure not to include edges along screen edge */
-ScrEdge *screen_find_active_scredge(bScreen *sc,
- const int winsize_x, const int winsize_y,
- const int mx, const int my)
+/**
+ * \param bounds_rect: Either window or screen bounds. Used to exclude edges along window/screen edges.
+ */
+ScrEdge *screen_area_map_find_active_scredge(
+ const ScrAreaMap *area_map,
+ const rcti *bounds_rect,
+ const int mx, const int my)
{
- ScrEdge *se;
int safety = U.widget_unit / 10;
- if (safety < 2) safety = 2;
+ CLAMP_MIN(safety, 2);
- for (se = sc->edgebase.first; se; se = se->next) {
+ for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) {
if (scredge_is_horizontal(se)) {
- if (se->v1->vec.y > 0 && se->v1->vec.y < winsize_y - 1) {
+ if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) {
short min, max;
min = MIN2(se->v1->vec.x, se->v2->vec.x);
max = MAX2(se->v1->vec.x, se->v2->vec.x);
@@ -287,7 +135,7 @@ ScrEdge *screen_find_active_scredge(bScreen *sc,
}
}
else {
- if (se->v1->vec.x > 0 && se->v1->vec.x < winsize_x - 1) {
+ if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) {
short min, max;
min = MIN2(se->v1->vec.y, se->v2->vec.y);
max = MAX2(se->v1->vec.y, se->v2->vec.y);
@@ -301,23 +149,55 @@ ScrEdge *screen_find_active_scredge(bScreen *sc,
return NULL;
}
+/* need win size to make sure not to include edges along screen edge */
+ScrEdge *screen_find_active_scredge(
+ const wmWindow *win, const bScreen *screen,
+ const int mx, const int my)
+{
+ /* Use layout size (screen excluding global areas) for screen-layout area edges */
+ rcti screen_rect;
+ ScrEdge *se;
+
+ WM_window_screen_rect_calc(win, &screen_rect);
+ se = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my);
+
+ if (!se) {
+ /* Use entire window size (screen including global areas) for global area edges */
+ rcti win_rect;
+ WM_window_rect_calc(win, &win_rect);
+ se = screen_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my);
+ }
+ return se;
+}
+
/* adds no space data */
-static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
+static ScrArea *screen_addarea_ex(
+ ScrAreaMap *area_map,
+ ScrVert *bottom_left, ScrVert *top_left, ScrVert *top_right, ScrVert *bottom_right,
+ short spacetype)
{
ScrArea *sa = MEM_callocN(sizeof(ScrArea), "addscrarea");
- sa->v1 = v1;
- sa->v2 = v2;
- sa->v3 = v3;
- sa->v4 = v4;
- sa->headertype = headertype;
- sa->spacetype = sa->butspacetype = spacetype;
- BLI_addtail(&sc->areabase, sa);
+ sa->v1 = bottom_left;
+ sa->v2 = top_left;
+ sa->v3 = top_right;
+ sa->v4 = bottom_right;
+ sa->spacetype = spacetype;
+
+ BLI_addtail(&area_map->areabase, sa);
return sa;
}
+static ScrArea *screen_addarea(
+ bScreen *sc,
+ ScrVert *left_bottom, ScrVert *left_top, ScrVert *right_top, ScrVert *right_bottom,
+ short spacetype)
+{
+ return screen_addarea_ex(AREAMAP_FROM_SCREEN(sc), left_bottom, left_top, right_top, right_bottom,
+ spacetype);
+}
static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
{
@@ -346,24 +226,24 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac)
CLAMP(fac, 0.0f, 1.0f);
if (dir == 'h') {
- y = sa->v1->vec.y + fac * (sa->v2->vec.y - sa->v1->vec.y);
+ y = sa->v1->vec.y +
+ round_fl_to_short(fac * (float)(sa->v2->vec.y - sa->v1->vec.y));
if (y - sa->v1->vec.y < area_min_y)
y = sa->v1->vec.y + area_min_y;
else if (sa->v2->vec.y - y < area_min_y)
y = sa->v2->vec.y - area_min_y;
- else y -= (y % AREAGRID);
return y;
}
else {
- x = sa->v1->vec.x + fac * (sa->v4->vec.x - sa->v1->vec.x);
+ x = sa->v1->vec.x +
+ round_fl_to_short(fac * (float)(sa->v4->vec.x - sa->v1->vec.x));
if (x - sa->v1->vec.x < area_min_x)
x = sa->v1->vec.x + area_min_x;
else if (sa->v4->vec.x - x < area_min_x)
x = sa->v4->vec.x - area_min_x;
- else x -= (x % AREAGRID);
return x;
}
@@ -398,7 +278,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
if (fac > 0.5f) {
/* new areas: top */
- newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->spacetype);
/* area below */
sa->v2 = sv1;
@@ -406,7 +286,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
}
else {
/* new areas: bottom */
- newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sa->v1, sv1, sv2, sa->v4, sa->spacetype);
/* area above */
sa->v1 = sv1;
@@ -430,7 +310,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
if (fac > 0.5f) {
/* new areas: right */
- newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sv1, sv2, sa->v3, sa->v4, sa->spacetype);
/* area left */
sa->v3 = sv2;
@@ -438,7 +318,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
}
else {
/* new areas: left */
- newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
+ newa = screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->spacetype);
/* area right */
sa->v1 = sv1;
@@ -450,33 +330,29 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
/* remove double vertices en edges */
if (merge)
- removedouble_scrverts(sc);
- removedouble_scredges(sc);
- removenotused_scredges(sc);
+ BKE_screen_remove_double_scrverts(sc);
+ BKE_screen_remove_double_scredges(sc);
+ BKE_screen_remove_unused_scredges(sc);
return newa;
}
-/* empty screen, with 1 dummy area without spacedata */
-/* uses window size */
-bScreen *ED_screen_add(Main *bmain, wmWindow *win, Scene *scene, const char *name)
+/**
+ * Empty screen, with 1 dummy area without spacedata. Uses window size.
+ */
+bScreen *screen_add(Main *bmain, const char *name, const rcti *rect)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
bScreen *sc;
ScrVert *sv1, *sv2, *sv3, *sv4;
sc = BKE_libblock_alloc(bmain, ID_SCR, name, 0);
- sc->scene = scene;
sc->do_refresh = true;
sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
- sc->winid = win->winid;
- sv1 = screen_addvert(sc, 0, 0);
- sv2 = screen_addvert(sc, 0, winsize_y - 1);
- sv3 = screen_addvert(sc, winsize_x - 1, winsize_y - 1);
- sv4 = screen_addvert(sc, winsize_x - 1, 0);
+ sv1 = screen_addvert(sc, rect->xmin, rect->ymin);
+ sv2 = screen_addvert(sc, rect->xmin, rect->ymax - 1);
+ sv3 = screen_addvert(sc, rect->xmax - 1, rect->ymax - 1);
+ sv4 = screen_addvert(sc, rect->xmax - 1, rect->ymin);
screen_addedge(sc, sv1, sv2);
screen_addedge(sc, sv2, sv3);
@@ -484,12 +360,12 @@ bScreen *ED_screen_add(Main *bmain, wmWindow *win, Scene *scene, const char *nam
screen_addedge(sc, sv4, sv1);
/* dummy type, no spacedata */
- screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY);
+ screen_addarea(sc, sv1, sv2, sv3, sv4, SPACE_EMPTY);
return sc;
}
-static void screen_copy(bScreen *to, bScreen *from)
+void screen_data_copy(bScreen *to, bScreen *from)
{
ScrVert *s1, *s2;
ScrEdge *se;
@@ -511,7 +387,7 @@ static void screen_copy(bScreen *to, bScreen *from)
for (se = to->edgebase.first; se; se = se->next) {
se->v1 = se->v1->newv;
se->v2 = se->v2->newv;
- sortscrvert(&(se->v1), &(se->v2));
+ BKE_screen_sort_scrvert(&(se->v1), &(se->v2));
}
saf = from->areabase.first;
@@ -532,7 +408,16 @@ static void screen_copy(bScreen *to, bScreen *from)
/* put at zero (needed?) */
for (s1 = from->vertbase.first; s1; s1 = s1->next)
s1->newv = NULL;
+}
+/**
+ * Prepare a newly created screen for initializing it as active screen.
+ */
+void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new)
+{
+ screen_new->winid = win->winid;
+ screen_new->do_refresh = true;
+ screen_new->do_draw = true;
}
@@ -611,15 +496,17 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2)
}
screen_delarea(C, scr, sa2);
- removedouble_scrverts(scr);
+ BKE_screen_remove_double_scrverts(scr);
+ /* Update preview thumbnail */
+ BKE_icon_changed(scr->id.icon_id);
return 1;
}
-void select_connected_scredge(bScreen *sc, ScrEdge *edge)
+void select_connected_scredge(const wmWindow *win, ScrEdge *edge)
{
+ bScreen *sc = WM_window_get_active_screen(win);
ScrEdge *se;
- ScrVert *sv;
int oneselected;
char dir;
@@ -629,10 +516,8 @@ void select_connected_scredge(bScreen *sc, ScrEdge *edge)
if (edge->v1->vec.x == edge->v2->vec.x) dir = 'v';
else dir = 'h';
- sv = sc->vertbase.first;
- while (sv) {
+ ED_screen_verts_iter(win, sc, sv) {
sv->flag = 0;
- sv = sv->next;
}
edge->v1->flag = 1;
@@ -662,18 +547,24 @@ void select_connected_scredge(bScreen *sc, ScrEdge *edge)
}
}
-/* test if screen vertices should be scaled */
-static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
+/**
+ * Test if screen vertices should be scaled and do if needed.
+ */
+static void screen_vertices_scale(
+ const wmWindow *win, bScreen *sc,
+ const rcti *window_rect, const rcti *screen_rect)
{
/* clamp Y size of header sized areas when expanding windows
* avoids annoying empty space around file menu */
#define USE_HEADER_SIZE_CLAMP
const int headery_init = ED_area_headersize();
+ const int screen_size_x = BLI_rcti_size_x(screen_rect);
+ const int screen_size_y = BLI_rcti_size_y(screen_rect);
ScrVert *sv = NULL;
ScrArea *sa;
- int winsize_x_prev, winsize_y_prev;
- float facx, facy, tempf, min[2], max[2];
+ int screen_size_x_prev, screen_size_y_prev;
+ float min[2], max[2];
/* calculate size */
min[0] = min[1] = 20000.0f;
@@ -684,14 +575,8 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
minmax_v2v2_v2(min, max, fv);
}
- /* always make 0.0 left under */
- for (sv = sc->vertbase.first; sv; sv = sv->next) {
- sv->vec.x -= min[0];
- sv->vec.y -= min[1];
- }
-
- winsize_x_prev = (max[0] - min[0]) + 1;
- winsize_y_prev = (max[1] - min[1]) + 1;
+ screen_size_x_prev = (max[0] - min[0]) + 1;
+ screen_size_y_prev = (max[1] - min[1]) + 1;
#ifdef USE_HEADER_SIZE_CLAMP
@@ -699,19 +584,19 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
#define TEMP_TOP 2
/* if the window's Y axis grows, clamp header sized areas */
- if (winsize_y_prev < winsize_y) { /* growing? */
+ if (screen_size_y_prev < screen_size_y) { /* growing? */
const int headery_margin_max = headery_init + 4;
for (sa = sc->areabase.first; sa; sa = sa->next) {
ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
sa->temp = 0;
if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) {
- if (sa->v2->vec.y == winsize_y_prev - 1) {
+ if (sa->v2->vec.y == max[1]) {
if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) {
sa->temp = TEMP_TOP;
}
}
- else if (sa->v1->vec.y == 0) {
+ else if (sa->v1->vec.y == min[1]) {
if ((sa->v2->vec.y - sa->v1->vec.y) < headery_margin_max) {
sa->temp = TEMP_BOTTOM;
}
@@ -722,33 +607,23 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
#endif
- if (winsize_x_prev != winsize_x || winsize_y_prev != winsize_y) {
- facx = ((float)winsize_x - 1) / ((float)winsize_x_prev - 1);
- facy = ((float)winsize_y - 1) / ((float)winsize_y_prev - 1);
+ if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) {
+ const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1);
+ const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1);
/* make sure it fits! */
for (sv = sc->vertbase.first; sv; sv = sv->next) {
- /* FIXME, this re-sizing logic is no good when re-sizing the window + redrawing [#24428]
- * need some way to store these as floats internally and re-apply from there. */
- tempf = ((float)sv->vec.x) * facx;
- sv->vec.x = (short)(tempf + 0.5f);
- //sv->vec.x += AREAGRID - 1;
- //sv->vec.x -= (sv->vec.x % AREAGRID);
+ sv->vec.x = screen_rect->xmin + round_fl_to_short((sv->vec.x - min[0]) * facx);
+ CLAMP(sv->vec.x, screen_rect->xmin, screen_rect->xmax - 1);
- CLAMP(sv->vec.x, 0, winsize_x - 1);
-
- tempf = ((float)sv->vec.y) * facy;
- sv->vec.y = (short)(tempf + 0.5f);
- //sv->vec.y += AREAGRID - 1;
- //sv->vec.y -= (sv->vec.y % AREAGRID);
-
- CLAMP(sv->vec.y, 0, winsize_y - 1);
+ sv->vec.y = screen_rect->ymin + round_fl_to_short((sv->vec.y - min[1]) * facy);
+ CLAMP(sv->vec.y, screen_rect->ymin, screen_rect->ymax - 1);
}
}
#ifdef USE_HEADER_SIZE_CLAMP
- if (winsize_y_prev < winsize_y) { /* growing? */
+ if (screen_size_y_prev < screen_size_y) { /* growing? */
for (sa = sc->areabase.first; sa; sa = sa->next) {
ScrEdge *se = NULL;
@@ -762,9 +637,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
if (sa->temp == TEMP_TOP) {
/* lower edge */
const int yval = sa->v2->vec.y - headery_init;
- se = screen_findedge(sc, sa->v4, sa->v1);
+ se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
if (se != NULL) {
- select_connected_scredge(sc, se);
+ select_connected_scredge(win, se);
}
for (sv = sc->vertbase.first; sv; sv = sv->next) {
if (sv != sa->v2 && sv != sa->v3) {
@@ -777,9 +652,9 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
else {
/* upper edge */
const int yval = sa->v1->vec.y + headery_init;
- se = screen_findedge(sc, sa->v2, sa->v3);
+ se = BKE_screen_find_edge(sc, sa->v2, sa->v3);
if (se != NULL) {
- select_connected_scredge(sc, se);
+ select_connected_scredge(win, se);
}
for (sv = sc->vertbase.first; sv; sv = sv->next) {
if (sv != sa->v1 && sv != sa->v4) {
@@ -806,21 +681,20 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
int headery = headery_init;
/* adjust headery if verts are along the edge of window */
- if (sa->v1->vec.y > 0)
+ if (sa->v1->vec.y > window_rect->ymin)
headery += U.pixelsize;
- if (sa->v2->vec.y < winsize_y - 1)
+ if (sa->v2->vec.y < window_rect->ymax)
headery += U.pixelsize;
if (sa->v2->vec.y - sa->v1->vec.y + 1 < headery) {
/* lower edge */
- ScrEdge *se = screen_findedge(sc, sa->v4, sa->v1);
+ ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1);
if (se && sa->v1 != sa->v2) {
- int yval;
+ const int yval = sa->v2->vec.y - headery + 1;
- select_connected_scredge(sc, se);
+ select_connected_scredge(win, se);
/* all selected vertices get the right offset */
- yval = sa->v2->vec.y - headery + 1;
for (sv = sc->vertbase.first; sv; sv = sv->next) {
/* if is a collapsed area */
if (sv != sa->v2 && sv != sa->v3) {
@@ -833,31 +707,45 @@ static void screen_test_scale(bScreen *sc, int winsize_x, int winsize_y)
}
}
+ /* Global areas have a fixed size that only changes with the DPI. Here we ensure that exactly this size is set. */
+ for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
+ continue;
+ }
+ /* width */
+ area->v1->vec.x = area->v2->vec.x = window_rect->xmin;
+ area->v3->vec.x = area->v4->vec.x = window_rect->xmax - 1;
+ /* height */
+ area->v1->vec.y = area->v4->vec.y = window_rect->ymin;
+ area->v2->vec.y = area->v3->vec.y = window_rect->ymax - 1;
+ switch (area->global->align) {
+ case GLOBAL_AREA_ALIGN_TOP:
+ area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - ED_area_global_size_y(area);
+ break;
+ case GLOBAL_AREA_ALIGN_BOTTOM:
+ area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + ED_area_global_size_y(area);
+ break;
+ }
+ }
}
+
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
-bScreen *ED_screen_duplicate(Main *bmain, wmWindow *win, bScreen *sc)
+/* screen sets cursor based on active region */
+static void region_cursor_set(wmWindow *win, bool swin_changed)
{
- bScreen *newsc;
-
- if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */
+ bScreen *screen = WM_window_get_active_screen(win);
- /* make new empty screen: */
- newsc = ED_screen_add(bmain, win, sc->scene, sc->id.name + 2);
- /* copy all data */
- screen_copy(newsc, sc);
-
- return newsc;
-}
-
-/* screen sets cursor based on swinid */
-static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
-{
- for (ScrArea *sa = win->screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid == swinid) {
+ if (ar == screen->active_region) {
if (swin_changed || (ar->type && ar->type->event_cursor)) {
+ if (ar->manipulator_map != NULL) {
+ if (WM_manipulatormap_cursor_set(ar->manipulator_map, win)) {
+ return;
+ }
+ }
ED_region_cursor_set(win, sa, ar);
}
return;
@@ -869,23 +757,24 @@ static void region_cursor_set(wmWindow *win, int swinid, int swin_changed)
void ED_screen_do_listen(bContext *C, wmNotifier *note)
{
wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = CTX_wm_screen(C);
/* generic notes */
switch (note->category) {
case NC_WM:
if (note->data == ND_FILEREAD)
- win->screen->do_draw = true;
+ screen->do_draw = true;
break;
case NC_WINDOW:
- win->screen->do_draw = true;
+ screen->do_draw = true;
break;
case NC_SCREEN:
if (note->action == NA_EDITED)
- win->screen->do_draw = win->screen->do_refresh = true;
+ screen->do_draw = screen->do_refresh = true;
break;
case NC_SCENE:
if (note->data == ND_MODE)
- region_cursor_set(win, note->swinid, true);
+ region_cursor_set(win, true);
break;
}
}
@@ -906,48 +795,40 @@ static void screen_refresh_headersizes(void)
/* for file read and first use, for scaling window, area moves */
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
{
+ bScreen *screen = WM_window_get_active_screen(win);
+
/* exception for bg mode, we only need the screen context */
if (!G.background) {
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
- ScrArea *sa;
- rcti winrct;
-
- winrct.xmin = 0;
- winrct.xmax = winsize_x - 1;
- winrct.ymin = 0;
- winrct.ymax = winsize_y - 1;
+ rcti window_rect, screen_rect;
/* header size depends on DPI, let's verify */
WM_window_set_dpi(win);
screen_refresh_headersizes();
- screen_test_scale(win->screen, winsize_x, winsize_y);
+ WM_window_rect_calc(win, &window_rect);
+ WM_window_screen_rect_calc(win, &screen_rect); /* Get screen bounds __after__ updating window DPI! */
- if (win->screen->mainwin == 0) {
- win->screen->mainwin = wm_subwindow_open(win, &winrct, false);
- }
- else {
- wm_subwindow_position(win, win->screen->mainwin, &winrct, false);
- }
+ screen_vertices_scale(win, screen, &window_rect, &screen_rect);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, area) {
/* set spacetype and region callbacks, calls init() */
/* sets subwindows for regions, adds handlers */
- ED_area_initialize(wm, win, sa);
+ ED_area_initialize(wm, win, area);
}
/* wake up animtimer */
- if (win->screen->animtimer)
- WM_event_timer_sleep(wm, win, win->screen->animtimer, false);
+ if (screen->animtimer)
+ WM_event_timer_sleep(wm, win, screen->animtimer, false);
}
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set screen\n", __func__);
}
- win->screen->do_refresh = false;
+ screen->do_refresh = false;
+ /* prevent multiwin errors */
+ screen->winid = win->winid;
- win->screen->context = ed_screen_context;
+ screen->context = ed_screen_context;
}
/* file read, set all screens, ... */
@@ -956,10 +837,23 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm)
wmWindow *win;
for (win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WM_window_set_active_workspace(win, bmain->workspaces.first);
+ }
- if (win->screen == NULL)
- win->screen = bmain->screen.first;
+ if (BLI_listbase_is_empty(&win->global_areas.areabase)) {
+ ED_screen_global_areas_create(win);
+ }
+ ED_screen_refresh(wm, win);
+ if (win->eventstate) {
+ ED_screen_set_active_region(NULL, win, &win->eventstate->x);
+ }
+ }
+}
+void ED_screen_ensure_updated(wmWindowManager *wm, wmWindow *win, bScreen *screen)
+{
+ if (screen->do_refresh) {
ED_screen_refresh(wm, win);
}
}
@@ -970,17 +864,17 @@ void ED_screens_initialize(Main *bmain, wmWindowManager *wm)
void ED_region_exit(bContext *C, ARegion *ar)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
ARegion *prevar = CTX_wm_region(C);
if (ar->type && ar->type->exit)
ar->type->exit(wm, ar);
CTX_wm_region_set(C, ar);
+
WM_event_remove_handlers(C, &ar->handlers);
- if (ar->swinid) {
- wm_subwindow_close(CTX_wm_window(C), ar->swinid);
- ar->swinid = 0;
- }
+ WM_event_modal_handler_region_replace(win, ar, NULL);
+ WM_draw_region_free(ar);
if (ar->headerstr) {
MEM_freeN(ar->headerstr);
@@ -988,16 +882,19 @@ void ED_region_exit(bContext *C, ARegion *ar)
}
if (ar->regiontimer) {
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), ar->regiontimer);
+ WM_event_remove_timer(wm, win, ar->regiontimer);
ar->regiontimer = NULL;
}
+ WM_msgbus_clear_by_owner(wm->message_bus, ar);
+
CTX_wm_region_set(C, prevar);
}
void ED_area_exit(bContext *C, ScrArea *sa)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
ScrArea *prevsa = CTX_wm_area(C);
ARegion *ar;
@@ -1005,10 +902,13 @@ void ED_area_exit(bContext *C, ScrArea *sa)
sa->type->exit(wm, sa);
CTX_wm_area_set(C, sa);
+
for (ar = sa->regionbase.first; ar; ar = ar->next)
ED_region_exit(C, ar);
WM_event_remove_handlers(C, &sa->handlers);
+ WM_event_modal_handler_area_replace(win, sa, NULL);
+
CTX_wm_area_set(C, prevsa);
}
@@ -1016,8 +916,6 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *prevwin = CTX_wm_window(C);
- ScrArea *sa;
- ARegion *ar;
CTX_wm_window_set(C, window);
@@ -1026,21 +924,23 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
screen->animtimer = NULL;
screen->scrubbing = false;
- if (screen->mainwin)
- wm_subwindow_close(window, screen->mainwin);
- screen->mainwin = 0;
- screen->subwinactive = 0;
+ screen->active_region = NULL;
- for (ar = screen->regionbase.first; ar; ar = ar->next)
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
ED_region_exit(C, ar);
-
- for (sa = screen->areabase.first; sa; sa = sa->next)
+ }
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
ED_area_exit(C, sa);
+ }
+ /* Don't use ED_screen_areas_iter here, it skips hidden areas. */
+ for (ScrArea *sa = window->global_areas.areabase.first; sa; sa = sa->next) {
+ ED_area_exit(C, sa);
+ }
/* mark it available for use for other windows */
screen->winid = 0;
- if (prevwin->screen->temp == 0) {
+ if (!WM_window_is_temp_screen(prevwin)) {
/* use previous window if possible */
CTX_wm_window_set(C, prevwin);
}
@@ -1054,16 +954,14 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
/* *********************************** */
/* case when on area-edge or in azones, or outside window */
-static void screen_cursor_set(wmWindow *win, const wmEvent *event)
+static void screen_cursor_set(wmWindow *win, const int xy[2])
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
+ const bScreen *screen = WM_window_get_active_screen(win);
AZone *az = NULL;
ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next)
- if ((az = ED_area_actionzone_find_xy(sa, &event->x)))
+ for (sa = screen->areabase.first; sa; sa = sa->next)
+ if ((az = ED_area_actionzone_find_xy(sa, xy)))
break;
if (sa) {
@@ -1077,7 +975,7 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event)
}
}
else {
- ScrEdge *actedge = screen_find_active_scredge(win->screen, winsize_x, winsize_y, event->x, event->y);
+ ScrEdge *actedge = screen_find_active_scredge(win, screen, xy[0], xy[1]);
if (actedge) {
if (scredge_is_horizontal(actedge))
@@ -1093,20 +991,20 @@ static void screen_cursor_set(wmWindow *win, const wmEvent *event)
/* called in wm_event_system.c. sets state vars in screen, cursors */
/* event type is mouse move */
-void ED_screen_set_subwinactive(bContext *C, const wmEvent *event)
+void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
{
- wmWindow *win = CTX_wm_window(C);
+ bScreen *scr = WM_window_get_active_screen(win);
- if (win->screen) {
- bScreen *scr = win->screen;
- ScrArea *sa;
+ if (scr) {
+ ScrArea *sa = NULL;
ARegion *ar;
- int oldswin = scr->subwinactive;
+ ARegion *old_ar = scr->active_region;
- for (sa = scr->areabase.first; sa; sa = sa->next) {
- if (event->x > sa->totrct.xmin && event->x < sa->totrct.xmax) {
- if (event->y > sa->totrct.ymin && event->y < sa->totrct.ymax) {
- if (NULL == ED_area_actionzone_refresh_xy(sa, &event->x)) {
+ ED_screen_areas_iter(win, scr, area_iter) {
+ if (xy[0] > area_iter->totrct.xmin && xy[0] < area_iter->totrct.xmax) {
+ if (xy[1] > area_iter->totrct.ymin && xy[1] < area_iter->totrct.ymax) {
+ if (ED_area_actionzone_refresh_xy(area_iter, xy) == NULL) {
+ sa = area_iter;
break;
}
}
@@ -1115,49 +1013,55 @@ void ED_screen_set_subwinactive(bContext *C, const wmEvent *event)
if (sa) {
/* make overlap active when mouse over */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) {
- scr->subwinactive = ar->swinid;
+ if (BLI_rcti_isect_pt_v(&ar->winrct, xy)) {
+ scr->active_region = ar;
break;
}
}
}
else
- scr->subwinactive = scr->mainwin;
+ scr->active_region = NULL;
/* check for redraw headers */
- if (oldswin != scr->subwinactive) {
+ if (old_ar != scr->active_region) {
- for (sa = scr->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, scr, area_iter) {
bool do_draw = false;
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid == oldswin || ar->swinid == scr->subwinactive)
+ for (ar = area_iter->regionbase.first; ar; ar = ar->next) {
+ if (ar == old_ar || ar == scr->active_region) {
do_draw = true;
+ }
+ }
if (do_draw) {
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->regiontype == RGN_TYPE_HEADER)
- ED_region_tag_redraw(ar);
+ for (ar = area_iter->regionbase.first; ar; ar = ar->next) {
+ if (ar->regiontype == RGN_TYPE_HEADER) {
+ ED_region_tag_redraw_no_rebuild(ar);
+ }
+ }
}
}
}
/* cursors, for time being set always on edges, otherwise aregion doesnt switch */
- if (scr->subwinactive == scr->mainwin) {
- screen_cursor_set(win, event);
+ if (scr->active_region == NULL) {
+ screen_cursor_set(win, xy);
}
else {
/* notifier invokes freeing the buttons... causing a bit too much redraws */
- if (oldswin != scr->subwinactive) {
- region_cursor_set(win, scr->subwinactive, true);
+ if (old_ar != scr->active_region) {
+ region_cursor_set(win, true);
/* this used to be a notifier, but needs to be done immediate
* because it can undo setting the right button as active due
* to delayed notifier handling */
- UI_screen_free_active_but(C, win->screen);
+ if (C) {
+ UI_screen_free_active_but(C, scr);
+ }
}
else
- region_cursor_set(win, scr->subwinactive, false);
+ region_cursor_set(win, false);
}
}
}
@@ -1176,183 +1080,199 @@ int ED_screen_area_active(const bContext *C)
return 1;
for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid == sc->subwinactive)
+ if (ar == sc->active_region)
return 1;
}
return 0;
}
/**
- * operator call, WM + Window + screen already existed before
- *
- * \warning Do NOT call in area/region queues!
- * \returns success.
+ * Add an area and geometry (screen-edges and -vertices) for it to \a area_map,
+ * with coordinates/dimensions matching \a rect.
*/
-bool ED_screen_set(bContext *C, bScreen *sc)
+static ScrArea *screen_area_create_with_geometry(
+ ScrAreaMap *area_map, const rcti *rect,
+ short spacetype)
{
- Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *oldscreen = CTX_wm_screen(C);
+ ScrVert *bottom_left = screen_addvert_ex(area_map, rect->xmin, rect->ymin);
+ ScrVert *top_left = screen_addvert_ex(area_map, rect->xmin, rect->ymax);
+ ScrVert *top_right = screen_addvert_ex(area_map, rect->xmax, rect->ymax);
+ ScrVert *bottom_right = screen_addvert_ex(area_map, rect->xmax, rect->ymin);
- /* validate screen, it's called with notifier reference */
- if (BLI_findindex(&bmain->screen, sc) == -1) {
- return true;
+ screen_addedge_ex(area_map, bottom_left, top_left);
+ screen_addedge_ex(area_map, top_left, top_right);
+ screen_addedge_ex(area_map, top_right, bottom_right);
+ screen_addedge_ex(area_map, bottom_right, bottom_left);
+
+ return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
+}
+
+static void screen_global_area_create(
+ wmWindow *win, eSpace_Type space_type, GlobalAreaAlign align, const rcti *rect,
+ const short height_cur, const short height_min, const short height_max)
+{
+ ScrArea *area = screen_area_create_with_geometry(&win->global_areas, rect, space_type);
+ SpaceType *stype = BKE_spacetype_from_id(space_type);
+ SpaceLink *slink = stype->new(area, WM_window_get_active_scene(win));
+
+ area->regionbase = slink->regionbase;
+
+ /* Data specific to global areas. */
+ area->global = MEM_callocN(sizeof(*area->global), __func__);
+ area->global->cur_fixed_height = height_cur;
+ area->global->size_max = height_max;
+ area->global->size_min = height_min;
+ area->global->align = align;
+
+ BLI_addhead(&area->spacedata, slink);
+ BLI_listbase_clear(&slink->regionbase);
+}
+
+static void screen_global_topbar_area_create(wmWindow *win)
+{
+ const short size_y = 2.25 * HEADERY;
+ rcti rect;
+
+ BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1);
+ rect.ymin = rect.ymax - size_y;
+
+ screen_global_area_create(win, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size_y, HEADERY, size_y);
+}
+
+static void screen_global_statusbar_area_create(wmWindow *win)
+{
+ const short size_y = HEADERY;
+ rcti rect;
+
+ BLI_rcti_init(&rect, 0, WM_window_pixels_x(win) - 1, 0, WM_window_pixels_y(win) - 1);
+ rect.ymax = rect.ymin + size_y;
+
+ screen_global_area_create(win, SPACE_STATUSBAR, GLOBAL_AREA_ALIGN_BOTTOM, &rect, size_y, size_y, size_y);
+}
+
+void ED_screen_global_areas_create(wmWindow *win)
+{
+ bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
+ if (screen->temp == 0) {
+ screen_global_topbar_area_create(win);
+ screen_global_statusbar_area_create(win);
}
+}
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- /* find associated full */
- bScreen *sc1;
- for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) {
- ScrArea *sa = sc1->areabase.first;
- if (sa->full == sc) {
- sc = sc1;
- break;
- }
+
+/* -------------------------------------------------------------------- */
+/* Screen changing */
+
+static bScreen *screen_fullscreen_find_associated_normal_screen(const Main *bmain, bScreen *screen)
+{
+ for (bScreen *screen_iter = bmain->screen.first; screen_iter; screen_iter = screen_iter->id.next) {
+ ScrArea *sa = screen_iter->areabase.first;
+ if (sa && sa->full == screen) {
+ return screen_iter;
}
}
+ return screen;
+}
+
+/**
+ * \return the screen to activate.
+ * \warning The returned screen may not always equal \a screen_new!
+ */
+bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, Main *bmain, bContext *C, wmWindow *win)
+{
+ /* validate screen, it's called with notifier reference */
+ if (BLI_findindex(&bmain->screen, screen_new) == -1) {
+ return NULL;
+ }
+
+ if (ELEM(screen_new->state, SCREENMAXIMIZED, SCREENFULL)) {
+ screen_new = screen_fullscreen_find_associated_normal_screen(bmain, screen_new);
+ }
+
/* check for valid winid */
- if (sc->winid != 0 && sc->winid != win->winid) {
- return false;
+ if (!(screen_new->winid == 0 || screen_new->winid == win->winid)) {
+ return NULL;
}
- if (oldscreen != sc) {
- wmTimer *wt = oldscreen->animtimer;
- ScrArea *sa;
- Scene *oldscene = oldscreen->scene;
+ if (screen_old != screen_new) {
+ wmTimer *wt = screen_old->animtimer;
/* remove handlers referencing areas in old screen */
- for (sa = oldscreen->areabase.first; sa; sa = sa->next) {
+ for (ScrArea *sa = screen_old->areabase.first; sa; sa = sa->next) {
WM_event_remove_area_handler(&win->modalhandlers, sa);
}
/* we put timer to sleep, so screen_exit has to think there's no timer */
- oldscreen->animtimer = NULL;
+ screen_old->animtimer = NULL;
if (wt) {
- WM_event_timer_sleep(wm, win, wt, true);
+ WM_event_timer_sleep(CTX_wm_manager(C), win, wt, true);
}
-
- ED_screen_exit(C, win, oldscreen);
+ ED_screen_exit(C, win, screen_old);
/* Same scene, "transfer" playback to new screen. */
if (wt) {
- if (oldscene == sc->scene) {
- sc->animtimer = wt;
- }
- /* Else, stop playback. */
- else {
- oldscreen->animtimer = wt;
- ED_screen_animation_play(C, 0, 0);
- }
+ screen_new->animtimer = wt;
}
- win->screen = sc;
- CTX_wm_window_set(C, win); // stores C->wm.screen... hrmf
-
- /* prevent multiwin errors */
- sc->winid = win->winid;
-
- ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
- WM_event_add_notifier(C, NC_WINDOW, NULL);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENSET, sc);
-
- /* makes button hilites work */
- WM_event_add_mousemove(C);
-
- /* Needed to make sure all the derivedMeshes are
- * up-to-date before viewport starts acquiring this.
- *
- * This is needed in cases when, for example, boolean
- * modifier uses operant from invisible layer.
- * Without this trick boolean wouldn't apply correct.
- *
- * Quite the same happens when setting screen's scene,
- * so perhaps this is in fact correct thing to do.
- */
- if (oldscene != sc->scene) {
- BKE_scene_set_background(bmain, sc->scene);
- }
-
- /* Always do visible update since it's possible new screen will
- * have different layers visible in 3D view-ports.
- * This is possible because of view3d.lock_camera_and_layers option.
- */
- DAG_on_visible_update(bmain, false);
+ return screen_new;
}
- return true;
+ return NULL;
}
-static bool ed_screen_used(wmWindowManager *wm, bScreen *sc)
+void screen_change_update(bContext *C, wmWindow *win, bScreen *sc)
{
- wmWindow *win;
+ Scene *scene = WM_window_get_active_scene(win);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
- for (win = wm->windows.first; win; win = win->next) {
- if (win->screen == sc) {
- return true;
- }
+ CTX_wm_window_set(C, win); /* stores C->wm.screen... hrmf */
- if (ELEM(win->screen->state, SCREENMAXIMIZED, SCREENFULL)) {
- ScrArea *sa = win->screen->areabase.first;
- if (sa->full == sc) {
- return true;
- }
- }
- }
+ ED_screen_refresh(CTX_wm_manager(C), win);
- return false;
+ BKE_screen_view3d_scene_sync(sc, scene); /* sync new screen with scene data */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTSET, layout);
+
+ /* makes button hilites work */
+ WM_event_add_mousemove(C);
}
-/* only call outside of area/region loops */
-bool ED_screen_delete(bContext *C, bScreen *sc)
+
+/**
+ * \brief Change the active screen.
+ *
+ * Operator call, WM + Window + screen already existed before
+ *
+ * \warning Do NOT call in area/region queues!
+ * \returns if screen changing was successful.
+ */
+bool ED_screen_change(bContext *C, bScreen *sc)
{
Main *bmain = CTX_data_main(C);
- wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- bScreen *newsc;
+ bScreen *screen_old = CTX_wm_screen(C);
+ bScreen *screen_new = screen_change_prepare(screen_old, sc, bmain, C, win);
- /* don't allow deleting temp fullscreens for now */
- if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
- return false;
- }
-
- /* screen can only be in use by one window at a time, so as
- * long as we are able to find a screen that is unused, we
- * can safely assume ours is not in use anywhere an delete it */
-
- for (newsc = sc->id.prev; newsc; newsc = newsc->id.prev)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
-
- if (!newsc) {
- for (newsc = sc->id.next; newsc; newsc = newsc->id.next)
- if (!ed_screen_used(wm, newsc) && !newsc->temp)
- break;
- }
-
- if (!newsc) {
- return false;
- }
+ if (screen_new) {
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WM_window_set_active_screen(win, workspace, sc);
+ screen_change_update(C, win, screen_new);
- ED_screen_set(C, newsc);
-
- if (win->screen != sc) {
- BKE_libblock_free(bmain, sc);
return true;
}
- else {
- return false;
- }
+
+ return false;
}
-static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa, View3D *v3d)
+static void screen_set_3dview_camera(Scene *scene, ViewLayer *view_layer, ScrArea *sa, View3D *v3d)
{
/* fix any cameras that are used in the 3d view but not in the scene */
BKE_screen_view3d_sync(v3d, scene);
- if (!v3d->camera || !BKE_scene_base_find(scene, v3d->camera)) {
- v3d->camera = BKE_scene_camera_find(sc->scene);
+ if (!v3d->camera || !BKE_view_layer_base_find(view_layer, v3d->camera)) {
+ v3d->camera = BKE_view_layer_camera_find(view_layer);
// XXX if (sc == curscreen) handle_view3d_lock();
if (!v3d->camera) {
ARegion *ar;
@@ -1376,100 +1296,21 @@ static void ed_screen_set_3dview_camera(Scene *scene, bScreen *sc, ScrArea *sa,
}
}
-/* only call outside of area/region loops */
-void ED_screen_set_scene(bContext *C, bScreen *screen, Scene *scene)
+void ED_screen_update_after_scene_change(const bScreen *screen, Scene *scene_new, ViewLayer *view_layer)
{
- Main *bmain = CTX_data_main(C);
- bScreen *sc;
-
- if (screen == NULL)
- return;
-
- if (ed_screen_used(CTX_wm_manager(C), screen)) {
- ED_object_editmode_exit(C, EM_FREEDATA);
- }
-
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
-
- if (scene != sc->scene) {
- /* all areas endlocalview */
- // XXX ScrArea *sa = sc->areabase.first;
- // while (sa) {
- // endlocalview(sa);
- // sa = sa->next;
- // }
- sc->scene = scene;
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ if (sl->spacetype == SPACE_VIEW3D) {
+ View3D *v3d = (View3D *)sl;
+ screen_set_3dview_camera(scene_new, view_layer, sa, v3d);
}
-
}
}
-
- // copy_view3d_lock(0); /* space.c */
-
- /* are there cameras in the views that are not in the scene? */
- for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- if ((U.flag & USER_SCENEGLOBAL) || sc == screen) {
- ScrArea *sa = sc->areabase.first;
- while (sa) {
- SpaceLink *sl = sa->spacedata.first;
- while (sl) {
- if (sl->spacetype == SPACE_VIEW3D) {
- View3D *v3d = (View3D *) sl;
- ed_screen_set_3dview_camera(scene, sc, sa, v3d);
-
- }
- sl = sl->next;
- }
- sa = sa->next;
- }
- }
- }
-
- CTX_data_scene_set(C, scene);
- BKE_scene_set_background(bmain, scene);
- DAG_on_visible_update(bmain, false);
-
- ED_render_engine_changed(bmain);
- ED_update_for_newframe(bmain, scene, 1);
-
- /* complete redraw */
- WM_event_add_notifier(C, NC_WINDOW, NULL);
-
-}
-
-/**
- * \note Only call outside of area/region loops
- * \return true if successful
- */
-bool ED_screen_delete_scene(bContext *C, Scene *scene)
-{
- Main *bmain = CTX_data_main(C);
- Scene *newscene;
-
- if (scene->id.prev)
- newscene = scene->id.prev;
- else if (scene->id.next)
- newscene = scene->id.next;
- else
- return false;
-
- ED_screen_set_scene(C, CTX_wm_screen(C), newscene);
-
- BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE);
-
- id_us_clear_real(&scene->id);
- if (scene->id.us == 0) {
- BKE_libblock_free(bmain, scene);
- }
-
- return true;
}
ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
{
wmWindow *win = CTX_wm_window(C);
- bScreen *screen = CTX_wm_screen(C);
ScrArea *newsa = NULL;
if (!sa || sa->full == NULL) {
@@ -1477,18 +1318,7 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
}
if (!newsa) {
- if (sa->full && (screen->state == SCREENMAXIMIZED)) {
- /* if this has been called from the temporary info header generated in
- * temp fullscreen layouts, find the correct fullscreen area to change
- * to create a new space inside */
- for (newsa = screen->areabase.first; newsa; newsa = newsa->next) {
- if (!(sa->flag & AREA_TEMP_INFO))
- break;
- }
- }
- else {
- newsa = sa;
- }
+ newsa = sa;
}
BLI_assert(newsa);
@@ -1571,6 +1401,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
{
Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1592,9 +1423,10 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
if (sa && sa->full) {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
/* restoring back to SCREENNORMAL */
sc = sa->full; /* the old screen to restore */
- oldscreen = win->screen; /* the one disappearing */
+ oldscreen = WM_window_get_active_screen(win); /* the one disappearing */
sc->state = SCREENNORMAL;
@@ -1608,10 +1440,8 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
/* clear full screen state */
old->full = NULL;
- old->flag &= ~AREA_TEMP_INFO;
}
- sa->flag &= ~AREA_TEMP_INFO;
sa->full = NULL;
if (fullsa == NULL) {
@@ -1621,6 +1451,10 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
if (state == SCREENFULL) {
+ /* unhide global areas */
+ for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area; glob_area = glob_area->next) {
+ glob_area->global->flag &= ~GLOBAL_AREA_IS_HIDDEN;
+ }
/* restore the old side panels/header visibility */
for (ar = sa->regionbase.first; ar; ar = ar->next) {
ar->flag = ar->flagfullscreen;
@@ -1633,9 +1467,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
sc->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- ED_screen_set(C, sc);
+ ED_screen_change(C, sc);
- BKE_libblock_free(CTX_data_main(C), oldscreen);
+ BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old);
/* After we've restored back to SCREENNORMAL, we have to wait with
* screen handling as it uses the area coords which aren't updated yet.
@@ -1645,14 +1479,20 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
}
else {
/* change from SCREENNORMAL to new state */
+ WorkSpaceLayout *layout_new;
ScrArea *newa;
char newname[MAX_ID_NAME - 2];
- oldscreen = win->screen;
+ BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL));
+
+ oldscreen = WM_window_get_active_screen(win);
oldscreen->state = state;
BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
- sc = ED_screen_add(bmain, win, oldscreen->scene, newname);
+
+ layout_new = ED_workspace_layout_add(bmain, workspace, win, newname);
+
+ sc = BKE_workspace_layout_screen_get(layout_new);
sc->state = state;
sc->redraws_flag = oldscreen->redraws_flag;
sc->temp = oldscreen->temp;
@@ -1663,51 +1503,35 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
- if (!sa)
+ if (!sa || sa->global) {
sa = oldscreen->areabase.first;
-
- if (state == SCREENMAXIMIZED) {
- /* returns the top small area */
- newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
- ED_area_newspace(C, newa, SPACE_INFO, false);
-
- /* copy area */
- newa = newa->prev;
- ED_area_data_swap(newa, sa);
- sa->flag |= AREA_TEMP_INFO;
-
- sa->full = oldscreen;
- newa->full = oldscreen;
- newa->next->full = oldscreen; // XXX
}
- else if (state == SCREENFULL) {
- newa = (ScrArea *)sc->areabase.first;
- /* copy area */
- ED_area_data_swap(newa, sa);
- newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+ newa = (ScrArea *)sc->areabase.first;
+ /* copy area */
+ ED_area_data_swap(newa, sa);
+ newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+
+ if (state == SCREENFULL) {
+ /* temporarily hide global areas */
+ for (ScrArea *glob_area = win->global_areas.areabase.first; glob_area; glob_area = glob_area->next) {
+ glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN;
+ }
/* temporarily hide the side panels/header */
for (ar = newa->regionbase.first; ar; ar = ar->next) {
ar->flagfullscreen = ar->flag;
- if (ELEM(ar->regiontype,
- RGN_TYPE_UI,
- RGN_TYPE_HEADER,
- RGN_TYPE_TOOLS))
- {
+ if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_HEADER, RGN_TYPE_TOOLS)) {
ar->flag |= RGN_FLAG_HIDDEN;
}
}
-
- sa->full = oldscreen;
- newa->full = oldscreen;
- }
- else {
- BLI_assert(false);
}
- ED_screen_set(C, sc);
+ sa->full = oldscreen;
+ newa->full = oldscreen;
+
+ ED_screen_change(C, sc);
}
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
@@ -1794,7 +1618,7 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync,
if (sa)
spacetype = sa->spacetype;
- sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME));
+ sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA));
screen->animtimer->customdata = sad;
@@ -1842,13 +1666,10 @@ void ED_screen_animation_timer_update(bScreen *screen, int redraws, int refresh)
}
}
-/* results in fully updated anim system
- * screen can be NULL */
-void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
+/* results in fully updated anim system */
+void ED_update_for_newframe(Main *bmain, Depsgraph *depsgraph)
{
- wmWindowManager *wm = bmain->wm.first;
- wmWindow *window;
- int layers = 0;
+ Scene *scene = DEG_get_input_scene(depsgraph);
#ifdef DURIAN_CAMERA_SWITCH
void *camera = BKE_scene_camera_switch_find(scene);
@@ -1857,19 +1678,15 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
scene->camera = camera;
/* are there cameras in the views that are not in the scene? */
for (sc = bmain->screen.first; sc; sc = sc->id.next) {
- BKE_screen_view3d_scene_sync(sc);
+ BKE_screen_view3d_scene_sync(sc, scene);
}
}
#endif
ED_clip_update_frame(bmain, scene->r.cfra);
- /* get layers from all windows */
- for (window = wm->windows.first; window; window = window->next)
- layers |= BKE_screen_visible_layers(window->screen, scene);
-
/* this function applies the changes too */
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, layers);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
/* composite */
if (scene->use_nodes && scene->nodetree)
@@ -1890,11 +1707,10 @@ void ED_update_for_newframe(Main *bmain, Scene *scene, int UNUSED(mute))
/*
* return true if any active area requires to see in 3D
*/
-bool ED_screen_stereo3d_required(bScreen *screen)
+bool ED_screen_stereo3d_required(const bScreen *screen, const Scene *scene)
{
ScrArea *sa;
- Scene *sce = screen->scene;
- const bool is_multiview = (sce->r.scemode & R_MULTIVIEW) != 0;
+ const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0;
for (sa = screen->areabase.first; sa; sa = sa->next) {
switch (sa->spacetype) {
@@ -1969,3 +1785,40 @@ bool ED_screen_stereo3d_required(bScreen *screen)
return false;
}
+
+/**
+ * Find the scene displayed in \a screen.
+ * \note Assumes \a screen to be visible/active!
+ */
+
+Scene *ED_screen_scene_find_with_window(const bScreen *screen, const wmWindowManager *wm, struct wmWindow **r_window)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ if (r_window) {
+ *r_window = win;
+ }
+ return WM_window_get_active_scene(win);
+ }
+ }
+
+ BLI_assert(0);
+ return NULL;
+}
+
+
+Scene *ED_screen_scene_find(const bScreen *screen, const wmWindowManager *wm)
+{
+ return ED_screen_scene_find_with_window(screen, wm, NULL);
+}
+
+
+wmWindow *ED_screen_window_find(const bScreen *screen, const wmWindowManager *wm)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return win;
+ }
+ }
+ return NULL;
+}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 63d616e986e..2c343fb9d70 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,23 +44,28 @@ 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 screen_area_update_region_sizes(wmWindowManager *wm, wmWindow *win, ScrArea *area);
+void region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
/* screen_edit.c */
-ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
+bScreen *screen_add(struct Main *bmain, const char *name, const rcti *rect);
+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);
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);
int area_getorientation(ScrArea *sa, ScrArea *sb);
-void select_connected_scredge(bScreen *sc, ScrEdge *edge);
+void select_connected_scredge(const wmWindow *win, ScrEdge *edge);
-void removenotused_scrverts(bScreen *sc);
-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,
- const int winsize_x, const int winsize_y,
- const int mx, const int my);
+ScrEdge *screen_area_map_find_active_scredge(
+ const struct ScrAreaMap *area_map,
+ const rcti *bounds_rect,
+ const int mx, const int my);
+ScrEdge *screen_find_active_scredge(
+ const wmWindow *win, const bScreen *screen,
+ const int mx, const int my);
struct AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2]);
struct AZone *ED_area_actionzone_refresh_xy(ScrArea *sa, const int xy[2]);
@@ -77,5 +83,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 1f5b51d211c..d74a9ed288c 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -39,6 +39,7 @@
#include "BLT_translation.h"
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_lattice_types.h"
#include "DNA_object_types.h"
@@ -48,11 +49,14 @@
#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_fcurve.h"
#include "BKE_global.h"
+#include "BKE_icons.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_report.h"
@@ -61,10 +65,14 @@
#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_anim_api.h"
#include "ED_armature.h"
#include "ED_clip.h"
#include "ED_image.h"
@@ -134,7 +142,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;
}
@@ -200,7 +208,7 @@ int ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C);
- if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
+ if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO)))
return true;
}
@@ -208,11 +216,6 @@ int ED_operator_animview_active(bContext *C)
return 0;
}
-int ED_operator_timeline_active(bContext *C)
-{
- return ed_spacetype_test(C, SPACE_TIME);
-}
-
int ED_operator_outliner_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_OUTLINER);
@@ -291,11 +294,6 @@ int ED_operator_nla_active(bContext *C)
return ed_spacetype_test(C, SPACE_NLA);
}
-int ED_operator_logic_active(bContext *C)
-{
- return ed_spacetype_test(C, SPACE_LOGIC);
-}
-
int ED_operator_info_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_INFO);
@@ -552,8 +550,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);
}
}
}
@@ -561,6 +559,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);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -723,6 +727,68 @@ static AZone *area_actionzone_refresh_xy(ScrArea *sa, const int xy[2], const boo
break;
}
}
+ else if (az->type == AZONE_REGION_SCROLL) {
+ ARegion *ar = az->ar;
+ View2D *v2d = &ar->v2d;
+ const short isect_value = UI_view2d_mouse_in_scrollers(ar, v2d, xy[0], xy[1]);
+ if (test_only) {
+ if (isect_value != 0) {
+ break;
+ }
+ }
+ else {
+ bool redraw = false;
+
+ if (isect_value == 'h') {
+ if (az->direction == AZ_SCROLL_HOR) {
+ az->alpha = 1.0f;
+ v2d->alpha_hor = 255;
+ v2d->size_hor = V2D_SCROLL_HEIGHT;
+ redraw = true;
+ }
+ }
+ else if (isect_value == 'v') {
+ if (az->direction == AZ_SCROLL_VERT) {
+ az->alpha = 1.0f;
+ v2d->alpha_vert = 255;
+ v2d->size_vert = V2D_SCROLL_WIDTH;
+ redraw = true;
+ }
+ }
+ else {
+ const int local_xy[2] = {xy[0] - ar->winrct.xmin, xy[1] - ar->winrct.ymin};
+ float dist_fac = 0.0f, alpha = 0.0f;
+
+ if (az->direction == AZ_SCROLL_HOR) {
+ dist_fac = BLI_rcti_length_y(&v2d->hor, local_xy[1]) / AZONEFADEIN;
+ CLAMP(dist_fac, 0.0f, 1.0f);
+ alpha = 1.0f - dist_fac;
+
+ v2d->alpha_hor = alpha * 255;
+ v2d->size_hor = round_fl_to_int(
+ V2D_SCROLL_HEIGHT -
+ ((V2D_SCROLL_HEIGHT - V2D_SCROLL_HEIGHT_MIN) * dist_fac));
+ }
+ else if (az->direction == AZ_SCROLL_VERT) {
+ dist_fac = BLI_rcti_length_x(&v2d->vert, local_xy[0]) / AZONEFADEIN;
+ CLAMP(dist_fac, 0.0f, 1.0f);
+ alpha = 1.0f - dist_fac;
+
+ v2d->alpha_vert = alpha * 255;
+ v2d->size_vert = round_fl_to_int(
+ V2D_SCROLL_WIDTH -
+ ((V2D_SCROLL_WIDTH - V2D_SCROLL_WIDTH_MIN) * dist_fac));
+ }
+ az->alpha = alpha;
+ redraw = true;
+ }
+
+ if (redraw) {
+ ED_area_tag_redraw_no_rebuild(sa);
+ }
+ /* Don't return! */
+ }
+ }
}
}
@@ -794,6 +860,9 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
actionzone_exit(op);
return OPERATOR_FINISHED;
}
+ else if (ELEM(sad->az->type, AZONE_REGION_SCROLL)) {
+ return OPERATOR_PASS_THROUGH;
+ }
else {
/* add modal handler */
WM_event_add_modal_handler(C, op);
@@ -805,11 +874,8 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
sActionzoneData *sad = op->customdata;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
switch (event->type) {
case MOUSEMOVE:
@@ -830,10 +896,15 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
sad->gesture_dir = 'w';
if (sad->az->type == AZONE_AREA) {
+ const wmWindow *win = CTX_wm_window(C);
+ rcti screen_rect;
+
+ WM_window_screen_rect_calc(win, &screen_rect);
/* once we drag outside the actionzone, register a gesture
* check we're not on an edge so join finds the other area */
is_gesture = ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
- (screen_find_active_scredge(sc, winsize_x, winsize_y, event->x, event->y) == NULL));
+ (screen_area_map_find_active_scredge(
+ AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y) == NULL));
}
else {
const int delta_min = 1;
@@ -1023,13 +1094,17 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- 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! */
@@ -1056,9 +1131,13 @@ 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(bmain, newwin, CTX_data_scene(C), sc->id.name + 2);
- newwin->screen = newsc;
+ layout_new = ED_workspace_layout_add(bmain, 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);
@@ -1126,32 +1205,82 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
*/
typedef struct sAreaMoveData {
- int bigger, smaller, origval;
+ int bigger, smaller, origval, step;
char dir;
- bool do_snap;
+ enum AreaMoveSnapType {
+ /* Snapping disabled */
+ SNAP_NONE = 0,
+ /* Snap to an invisible grid with a unit defined in AREAGRID */
+ SNAP_AREAGRID,
+ /* Snap to mid-point and adjacent edges. */
+ SNAP_MIDPOINT_AND_ADJACENT,
+ /* Snap to either bigger or smaller, nothing in-between (used for
+ * global areas). This has priority over other snap types, if it is
+ * used, toggling SNAP_MIDPOINT_AND_ADJACENT doesn't work. */
+ SNAP_BIGGER_SMALLER_ONLY,
+ } snap_type;
} sAreaMoveData;
/* helper call to move area-edge, sets limits
- * need window size in order to get correct limits */
-static void area_move_set_limits(bScreen *sc, int dir,
- const int winsize_x, const int winsize_y,
- int *bigger, int *smaller)
+ * need window bounds in order to get correct limits */
+static void area_move_set_limits(
+ wmWindow *win, bScreen *sc, int dir,
+ const rcti *screen_rect,
+ int *bigger, int *smaller,
+ bool *use_bigger_smaller_snap)
{
- ScrArea *sa;
int areaminy = ED_area_headersize();
int areamin;
/* we check all areas and test for free space with MINSIZE */
*bigger = *smaller = 100000;
- for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (use_bigger_smaller_snap != NULL) {
+ *use_bigger_smaller_snap = false;
+ for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
+ const int size_min = round_fl_to_int(area->global->size_min * UI_DPI_FAC);
+ const int size_max = round_fl_to_int(area->global->size_max * UI_DPI_FAC);
+
+ /* logic here is only tested for lower edge :) */
+ /* left edge */
+ if ((area->v1->editflag && area->v2->editflag)) {
+ *smaller = area->v4->vec.x - size_max;
+ *bigger = area->v4->vec.x - size_min;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ /* top edge */
+ else if ((area->v2->editflag && area->v3->editflag)) {
+ *smaller = area->v1->vec.y + size_min;
+ *bigger = area->v1->vec.y + size_max;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ /* right edge */
+ else if ((area->v3->editflag && area->v4->editflag)) {
+ *smaller = area->v1->vec.x + size_min;
+ *bigger = area->v1->vec.x + size_max;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ /* lower edge */
+ else if ((area->v4->editflag && area->v1->editflag)) {
+ *smaller = area->v2->vec.y - size_max;
+ *bigger = area->v2->vec.y - size_min;
+ *use_bigger_smaller_snap = true;
+ return;
+ }
+ }
+ }
+
+ for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
if (dir == 'h') {
int y1;
areamin = areaminy;
- if (sa->v1->vec.y > 0)
+ if (sa->v1->vec.y > screen_rect->ymin)
areamin += U.pixelsize;
- if (sa->v2->vec.y < winsize_y - 1)
+ if (sa->v2->vec.y < (screen_rect->ymax - 1))
areamin += U.pixelsize;
y1 = sa->v2->vec.y - sa->v1->vec.y + 1 - areamin;
@@ -1166,9 +1295,9 @@ static void area_move_set_limits(bScreen *sc, int dir,
int x1;
areamin = AREAMINX;
- if (sa->v1->vec.x > 0)
+ if (sa->v1->vec.x > screen_rect->xmin)
areamin += U.pixelsize;
- if (sa->v4->vec.x < winsize_x - 1)
+ if (sa->v4->vec.x < (screen_rect->xmax - 1))
areamin += U.pixelsize;
x1 = sa->v4->vec.x - sa->v1->vec.x + 1 - areamin;
@@ -1190,9 +1319,7 @@ static int area_move_init(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
ScrEdge *actedge;
sAreaMoveData *md;
- ScrVert *v1;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
+ rcti screen_rect;
int x, y;
/* required properties */
@@ -1200,7 +1327,7 @@ static int area_move_init(bContext *C, wmOperator *op)
y = RNA_int_get(op->ptr, "y");
/* setup */
- actedge = screen_find_active_scredge(sc, winsize_x, winsize_y, x, y);
+ actedge = screen_find_active_scredge(win, sc, x, y);
if (actedge == NULL) return 0;
md = MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
@@ -1210,42 +1337,67 @@ static int area_move_init(bContext *C, wmOperator *op)
if (md->dir == 'h') md->origval = actedge->v1->vec.y;
else md->origval = actedge->v1->vec.x;
- select_connected_scredge(sc, actedge);
- /* now all vertices with 'flag==1' are the ones that can be moved. Move this to editflag */
- for (v1 = sc->vertbase.first; v1; v1 = v1->next)
+ select_connected_scredge(win, actedge);
+ /* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */
+ ED_screen_verts_iter(win, sc, v1) {
v1->editflag = v1->flag;
+ }
+
+ WM_window_screen_rect_calc(win, &screen_rect);
- area_move_set_limits(sc, md->dir, winsize_x, winsize_y, &md->bigger, &md->smaller);
+ bool use_bigger_smaller_snap = false;
+ area_move_set_limits(win, sc, md->dir, &screen_rect,
+ &md->bigger, &md->smaller,
+ &use_bigger_smaller_snap);
+
+ md->snap_type = use_bigger_smaller_snap ? SNAP_BIGGER_SMALLER_ONLY : SNAP_AREAGRID;
return 1;
}
static int area_snap_calc_location(
- const bScreen *sc, const int delta,
- const int origval, const int dir,
+ const bScreen *sc, const enum AreaMoveSnapType snap_type,
+ const int delta, const int origval, const int dir,
const int bigger, const int smaller)
{
+ BLI_assert(snap_type != SNAP_NONE);
int final_loc = -1;
-
const int m_loc = origval + delta;
- const int axis = (dir == 'v') ? 0 : 1;
- int snap_dist;
- int dist;
- {
- /* Test the snap to middle. */
- int middle = origval + (bigger - smaller) / 2;
- middle -= (middle % AREAGRID);
- snap_dist = abs(m_loc - middle);
- final_loc = middle;
- }
+ switch (snap_type) {
+ case SNAP_AREAGRID:
+ final_loc = m_loc;
+ if (delta != bigger && delta != -smaller) {
+ final_loc -= (m_loc % AREAGRID);
+ }
+ break;
- for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
- if (v1->editflag) {
- const int v_loc = (&v1->vec.x)[!axis];
+ case SNAP_BIGGER_SMALLER_ONLY:
+ final_loc = (m_loc >= bigger) ? bigger : smaller;
+ break;
+
+ case SNAP_MIDPOINT_AND_ADJACENT:
+ {
+ const int axis = (dir == 'v') ? 0 : 1;
+ int snap_dist;
+ int dist;
+ {
+ /* Test the snap to middle. */
+ int middle = origval + (bigger - smaller) / 2;
+ snap_dist = abs(m_loc - middle);
+ final_loc = middle;
+ }
- for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
- if (!v2->editflag) {
+ for (const ScrVert *v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ if (!v1->editflag) {
+ continue;
+ }
+ const int v_loc = (&v1->vec.x)[!axis];
+
+ for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
+ if (v2->editflag) {
+ continue;
+ }
if (v_loc == (&v2->vec.x)[!axis]) {
const int v_loc2 = (&v2->vec.x)[axis];
/* Do not snap to the vertices at the ends. */
@@ -1259,7 +1411,10 @@ static int area_snap_calc_location(
}
}
}
+ break;
}
+ case SNAP_NONE:
+ break;
}
return final_loc;
@@ -1270,29 +1425,26 @@ static void area_move_apply_do(
const bContext *C, int delta,
const int origval, const int dir,
const int bigger, const int smaller,
- const bool do_snap)
+ const enum AreaMoveSnapType snap_type)
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
- ScrVert *v1;
bool doredraw = false;
CLAMP(delta, -smaller, bigger);
short final_loc = -1;
- if (do_snap) {
- final_loc = area_snap_calc_location(sc, delta, origval, dir, bigger, smaller);
+ if (snap_type == SNAP_NONE) {
+ final_loc = origval + delta;
}
else {
- final_loc = origval + delta;
- if (delta != bigger && delta != -smaller) {
- final_loc -= (final_loc % AREAGRID);
- }
+ final_loc = area_snap_calc_location(sc, snap_type, delta, origval, dir, bigger, smaller);
}
BLI_assert(final_loc != -1);
short axis = (dir == 'v') ? 0 : 1;
- for (v1 = sc->vertbase.first; v1; v1 = v1->next) {
+ ED_screen_verts_iter(win, sc, v1) {
if (v1->editflag) {
short oldval = (&v1->vec.x)[axis];
(&v1->vec.x)[axis] = final_loc;
@@ -1307,12 +1459,26 @@ static void area_move_apply_do(
/* only redraw if we actually moved a screen vert, for AREAGRID */
if (doredraw) {
- for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
+ bool redraw_all = false;
+ ED_screen_areas_iter(win, sc, sa) {
if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) {
+ if (ED_area_is_global(sa)) {
+ sa->global->cur_fixed_height = round_fl_to_int((sa->v2->vec.y - sa->v1->vec.y) / UI_DPI_FAC);
+ sc->do_refresh = true;
+ redraw_all = true;
+ }
+ ED_area_tag_redraw(sa);
+ }
+ }
+ if (redraw_all) {
+ ED_screen_areas_iter(win, sc, sa) {
ED_area_tag_redraw(sa);
}
}
+
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL); /* redraw everything */
+ /* Update preview thumbnail */
+ BKE_icon_changed(sc->id.icon_id);
}
}
@@ -1321,7 +1487,7 @@ static void area_move_apply(bContext *C, wmOperator *op)
sAreaMoveData *md = op->customdata;
int delta = RNA_int_get(op->ptr, "delta");
- area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->do_snap);
+ area_move_apply_do(C, delta, md->origval, md->dir, md->bigger, md->smaller, md->snap_type);
}
static void area_move_exit(bContext *C, wmOperator *op)
@@ -1331,8 +1497,8 @@ static void area_move_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
/* this makes sure aligned edges will result in aligned grabbing */
- removedouble_scrverts(CTX_wm_screen(C));
- removedouble_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_double_scrverts(CTX_wm_screen(C));
+ BKE_screen_remove_double_scredges(CTX_wm_screen(C));
}
static int area_move_exec(bContext *C, wmOperator *op)
@@ -1400,10 +1566,15 @@ static int area_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case KM_MODAL_SNAP_ON:
- md->do_snap = true;
+ if (md->snap_type != SNAP_BIGGER_SMALLER_ONLY) {
+ md->snap_type = SNAP_MIDPOINT_AND_ADJACENT;
+ }
break;
+
case KM_MODAL_SNAP_OFF:
- md->do_snap = false;
+ if (md->snap_type != SNAP_BIGGER_SMALLER_ONLY) {
+ md->snap_type = SNAP_AREAGRID;
+ }
break;
}
break;
@@ -1522,7 +1693,7 @@ static int area_split_init(bContext *C, wmOperator *op)
{
ScrArea *sa = CTX_wm_area(C);
sAreaSplitData *sd;
- int areaminy = ED_area_headersize() + 1;
+ int areaminy = ED_area_headersize();
int dir;
/* required context */
@@ -1540,8 +1711,14 @@ static int area_split_init(bContext *C, wmOperator *op)
op->customdata = sd;
sd->sarea = sa;
- sd->origsize = dir == 'v' ? sa->winx : sa->winy;
- sd->origmin = dir == 'v' ? sa->totrct.xmin : sa->totrct.ymin;
+ if (dir == 'v') {
+ sd->origmin = sa->v1->vec.x;
+ sd->origsize = sa->v4->vec.x - sd->origmin;
+ }
+ else {
+ sd->origmin = sa->v1->vec.y;
+ sd->origsize = sa->v2->vec.y - sd->origmin;
+ }
return 1;
}
@@ -1560,16 +1737,16 @@ static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
ScrVert *sbv4 = sb->v4;
if (sav1 == sbv4 && sav2 == sbv3) { /* sa to right of sb = W */
- return screen_findedge(screen, sav1, sav2);
+ return BKE_screen_find_edge(screen, sav1, sav2);
}
else if (sav2 == sbv1 && sav3 == sbv4) { /* sa to bottom of sb = N */
- return screen_findedge(screen, sav2, sav3);
+ return BKE_screen_find_edge(screen, sav2, sav3);
}
else if (sav3 == sbv2 && sav4 == sbv1) { /* sa to left of sb = E */
- return screen_findedge(screen, sav3, sav4);
+ return BKE_screen_find_edge(screen, sav3, sav4);
}
else if (sav1 == sbv2 && sav4 == sbv3) { /* sa on top of sb = S*/
- return screen_findedge(screen, sav1, sav4);
+ return BKE_screen_find_edge(screen, sav1, sav4);
}
return NULL;
@@ -1608,6 +1785,8 @@ 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;
}
@@ -1633,8 +1812,8 @@ static void area_split_exit(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
/* this makes sure aligned edges will result in aligned grabbing */
- removedouble_scrverts(CTX_wm_screen(C));
- removedouble_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_double_scrverts(CTX_wm_screen(C));
+ BKE_screen_remove_double_scredges(CTX_wm_screen(C));
}
static void area_split_preview_update_cursor(bContext *C, wmOperator *op)
@@ -1650,14 +1829,15 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
wmWindow *win = CTX_wm_window(C);
bScreen *sc = CTX_wm_screen(C);
sAreaSplitData *sd;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
+ rcti screen_rect;
int dir;
/* no full window splitting allowed */
if (sc->state != SCREENNORMAL)
return OPERATOR_CANCELLED;
+ WM_window_screen_rect_calc(win, &screen_rect);
+
if (event->type == EVT_ACTIONZONE_AREA) {
sActionzoneData *sad = event->customdata;
@@ -1704,7 +1884,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
else
y = event->x;
- actedge = screen_find_active_scredge(sc, winsize_x, winsize_y, x, y);
+ actedge = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, x, y);
if (actedge == NULL)
return OPERATOR_CANCELLED;
@@ -1724,7 +1904,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* do the split */
if (area_split_apply(C, op)) {
- area_move_set_limits(sc, dir, winsize_x, winsize_y, &sd->bigger, &sd->smaller);
+ area_move_set_limits(win, sc, dir, &screen_rect, &sd->bigger, &sd->smaller, NULL);
/* add temp handler for edge move or cancel */
WM_event_add_modal_handler(C, op);
@@ -1842,10 +2022,11 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->previewmode == 0) {
if (sd->do_snap) {
const int snap_loc = area_snap_calc_location(
- CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->bigger, sd->smaller);
+ CTX_wm_screen(C), SNAP_MIDPOINT_AND_ADJACENT, sd->delta, sd->origval, dir,
+ sd->bigger, sd->smaller);
sd->delta = snap_loc - sd->origval;
}
- area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, false);
+ area_move_apply_do(C, sd->delta, sd->origval, dir, sd->bigger, sd->smaller, SNAP_NONE);
}
else {
if (sd->sarea) {
@@ -1857,19 +2038,20 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (sd->sarea) {
ScrArea *sa = sd->sarea;
if (dir == 'v') {
- sd->origsize = sa->winx;
- sd->origmin = sa->totrct.xmin;
+ sd->origmin = sa->v1->vec.x;
+ sd->origsize = sa->v4->vec.x - sd->origmin;
}
else {
- sd->origsize = sa->winy;
- sd->origmin = sa->totrct.ymin;
+ sd->origmin = sa->v1->vec.y;
+ sd->origsize = sa->v2->vec.y - sd->origmin;
}
if (sd->do_snap) {
sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 1;
const int snap_loc = area_snap_calc_location(
- CTX_wm_screen(C), sd->delta, sd->origval, dir, sd->origmin + sd->origsize, -sd->origmin);
+ CTX_wm_screen(C), SNAP_MIDPOINT_AND_ADJACENT, sd->delta, sd->origval, dir,
+ sd->origmin + sd->origsize, -sd->origmin);
sa->v1->editflag = sa->v2->editflag = sa->v3->editflag = sa->v4->editflag = 0;
sd->delta = snap_loc - sd->origval;
@@ -1878,7 +2060,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;
@@ -2047,7 +2229,8 @@ static int region_scale_get_maxsize(RegionMoveData *rmd)
if (rmd->ar->regiontype == RGN_TYPE_TOOL_PROPS) {
/* this calculation seems overly verbose
* can someone explain why this method is necessary? - campbell */
- maxsize = rmd->maxsize - ((rmd->sa->headertype == HEADERTOP) ? UI_UNIT_Y * 2 : UI_UNIT_Y) - (UI_UNIT_Y / 4);
+ const bool top_header = ED_area_header_alignment(rmd->sa) == RGN_ALIGN_TOP;
+ maxsize = rmd->maxsize - ((top_header) ? UI_UNIT_Y * 2 : UI_UNIT_Y) - (UI_UNIT_Y / 4);
}
return maxsize;
@@ -2091,7 +2274,9 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* execute the events */
switch (event->type) {
case MOUSEMOVE:
-
+ {
+ const float aspect = BLI_rctf_size_x(&rmd->ar->v2d.cur) / (BLI_rcti_size_x(&rmd->ar->v2d.mask) + 1);
+ const int snap_size_threshold = (U.widget_unit * 2) / aspect;
if (rmd->edge == AE_LEFT_TO_TOPRIGHT || rmd->edge == AE_RIGHT_TO_TOPLEFT) {
delta = event->x - rmd->origx;
if (rmd->edge == AE_LEFT_TO_TOPRIGHT) delta = -delta;
@@ -2100,6 +2285,13 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
delta /= UI_DPI_FAC;
rmd->ar->sizex = rmd->origval + delta;
+
+ if (rmd->ar->type->snap_size) {
+ short sizex_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizex, 0);
+ if (ABS(rmd->ar->sizex - sizex_test) < snap_size_threshold) {
+ rmd->ar->sizex = sizex_test;
+ }
+ }
CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
if (rmd->ar->sizex < UI_UNIT_X) {
@@ -2119,6 +2311,13 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
delta /= UI_DPI_FAC;
rmd->ar->sizey = rmd->origval + delta;
+
+ if (rmd->ar->type->snap_size) {
+ short sizey_test = rmd->ar->type->snap_size(rmd->ar, rmd->ar->sizey, 1);
+ if (ABS(rmd->ar->sizey - sizey_test) < snap_size_threshold) {
+ rmd->ar->sizey = sizey_test;
+ }
+ }
CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
/* note, 'UI_UNIT_Y/4' means you need to drag the header almost
@@ -2138,7 +2337,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
break;
-
+ }
case LEFTMOUSE:
if (event->val == KM_RELEASE) {
@@ -2201,16 +2400,15 @@ 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 &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ ELEM(sa->spacetype, SPACE_SEQ, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
(sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
{
float w = BLI_rctf_size_x(&ar->v2d.cur);
@@ -2521,64 +2719,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;
}
@@ -2634,6 +2784,15 @@ static int screen_maximize_area_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
+static int screen_maximize_area_poll(bContext *C)
+{
+ const bScreen *screen = CTX_wm_screen(C);
+ const ScrArea *area = CTX_wm_area(C);
+ return ED_operator_areaactive(C) &&
+ /* Don't allow maximizing global areas but allow minimizing from them. */
+ ((screen->state != SCREENNORMAL) || !ED_area_is_global(area));
+}
+
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
PropertyRNA *prop;
@@ -2643,7 +2802,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
ot->idname = "SCREEN_OT_screen_full_area";
ot->exec = screen_maximize_area_exec;
- ot->poll = ED_operator_areaactive;
+ ot->poll = screen_maximize_area_poll;
ot->flag = 0;
prop = RNA_def_boolean(ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels");
@@ -2776,9 +2935,9 @@ static void area_join_exit(bContext *C, wmOperator *op)
}
/* this makes sure aligned edges will result in aligned grabbing */
- removedouble_scredges(CTX_wm_screen(C));
- removenotused_scredges(CTX_wm_screen(C));
- removenotused_scrverts(CTX_wm_screen(C));
+ BKE_screen_remove_double_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_unused_scredges(CTX_wm_screen(C));
+ BKE_screen_remove_unused_scrverts(CTX_wm_screen(C));
}
static int area_join_exec(bContext *C, wmOperator *op)
@@ -2947,16 +3106,16 @@ static void SCREEN_OT_area_join(wmOperatorType *ot)
static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ const wmWindow *win = CTX_wm_window(C);
+ const bScreen *sc = CTX_wm_screen(C);
uiPopupMenu *pup;
uiLayout *layout;
PointerRNA ptr;
ScrEdge *actedge;
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
+ rcti screen_rect;
- actedge = screen_find_active_scredge(sc, winsize_x, winsize_y, event->x, event->y);
+ WM_window_screen_rect_calc(win, &screen_rect);
+ actedge = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y);
if (actedge == NULL) return OPERATOR_CANCELLED;
@@ -3360,6 +3519,18 @@ static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static int region_flip_poll(bContext *C)
+{
+ ScrArea *area = CTX_wm_area(C);
+
+ /* don't flip anything around in topbar */
+ if (area->spacetype == SPACE_TOPBAR) {
+ CTX_wm_operator_poll_msg_set(C, "Flipping regions in the Top-bar is not allowed");
+ return 0;
+ }
+
+ return ED_operator_areaactive(C);
+}
static void SCREEN_OT_region_flip(wmOperatorType *ot)
{
@@ -3370,7 +3541,7 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
/* api callbacks */
ot->exec = region_flip_exec;
- ot->poll = ED_operator_areaactive;
+ ot->poll = region_flip_poll;
ot->flag = 0;
}
@@ -3453,6 +3624,8 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
ARegion *ar = CTX_wm_region(C);
const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") : IFACE_("Flip to Top");
+ uiItemO(layout, IFACE_("Toggle Header"), ICON_NONE, "SCREEN_OT_header");
+
/* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
@@ -3463,12 +3636,11 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
uiItemS(layout);
- /* file browser should be fullscreen all the time, but other regions can be maximized/restored... */
- if (sa->spacetype != SPACE_FILE) {
- if (sa->full)
- uiItemO(layout, IFACE_("Tile Area"), ICON_NONE, "SCREEN_OT_screen_full_area");
- else
- uiItemO(layout, IFACE_("Maximize Area"), ICON_NONE, "SCREEN_OT_screen_full_area");
+ /* file browser should be fullscreen all the time, topbar should
+ * never be. But other regions can be maximized/restored... */
+ if (!ELEM(sa->spacetype, SPACE_FILE, SPACE_TOPBAR)) {
+ const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+ uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
}
}
@@ -3528,13 +3700,14 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws,
return 1;
break;
case SPACE_IPO:
- case SPACE_ACTION:
case SPACE_NLA:
if ((redraws & TIME_ALL_ANIM_WIN) || from_anim_edit)
return 1;
break;
- case SPACE_TIME:
- /* if only 1 window or 3d windows, we do timeline too */
+ case SPACE_ACTION:
+ /* if only 1 window or 3d windows, we do timeline too
+ * NOTE: Now we do do action editor in all these cases, since timeline is here
+ */
if ((redraws & (TIME_ALL_ANIM_WIN | TIME_REGION | TIME_ALL_3D_WIN)) || from_anim_edit)
return 1;
break;
@@ -3585,7 +3758,7 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws,
return 1;
}
else if (regiontype == RGN_TYPE_HEADER) {
- if (spacetype == SPACE_TIME)
+ if (spacetype == SPACE_ACTION)
return 1;
}
else if (regiontype == RGN_TYPE_PREVIEW) {
@@ -3615,6 +3788,7 @@ 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);
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -3725,10 +3899,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, 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;
@@ -3744,7 +3920,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
/* do follow here if editor type supports it */
if ((sad->redraws & TIME_FOLLOW)) {
if ((ar->regiontype == RGN_TYPE_WINDOW &&
- ELEM(sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ ELEM(sa->spacetype, SPACE_SEQ, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
(sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
{
float w = BLI_rctf_size_x(&ar->v2d.cur);
@@ -3808,11 +3984,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;
}
}
@@ -3821,11 +3997,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;
}
}
@@ -3847,7 +4023,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
else {
- int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
+ int refresh = SPACE_ACTION; /* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) /* XXX only play audio forwards!? */
BKE_sound_play_scene(scene);
@@ -4049,7 +4225,7 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int sizex = 800 * UI_DPI_FAC;
- int sizey = 480 * UI_DPI_FAC;
+ int sizey = 500 * UI_DPI_FAC;
/* changes context! */
if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_USERPREFS) != NULL) {
@@ -4077,118 +4253,101 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name New Screen Operator
+/** \name Show Drivers Editor Operator
* \{ */
-static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
+static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- Main *bmain = CTX_data_main(C);
- wmWindow *win = CTX_wm_window(C);
- bScreen *sc = CTX_wm_screen(C);
+ PointerRNA ptr = {{NULL}};
+ PropertyRNA *prop = NULL;
+ int index = -1;
+ uiBut *but = NULL;
- sc = ED_screen_duplicate(bmain, win, sc);
- WM_event_add_notifier(C, NC_SCREEN | ND_SCREENBROWSE, sc);
+ int sizex = 900 * UI_DPI_FAC;
+ int sizey = 580 * UI_DPI_FAC;
- return OPERATOR_FINISHED;
-}
+ /* Get active property to show driver for
+ * - Need to grab it first, or else this info disappears
+ * after we've created the window
+ */
+ but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
-static void SCREEN_OT_new(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "New Screen";
- ot->description = "Add a new screen";
- ot->idname = "SCREEN_OT_new";
+ /* changes context! */
+ if (WM_window_open_temp(C, event->x, event->y, sizex, sizey, WM_WINDOW_DRIVERS) != NULL) {
+ /* activate driver F-Curve for the property under the cursor */
+ if (but) {
+ FCurve *fcu;
+ bool driven, special;
+
+ fcu = rna_get_fcurve_context_ui(C,
+ &ptr, prop, index,
+ NULL, NULL, &driven, &special);
+ if (fcu) {
+ /* Isolate this F-Curve... */
+ bAnimContext ac;
+ if (ANIM_animdata_get_context(C, &ac)) {
+ int filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS;
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_set_active_channel(&ac, ac.data, ac.datatype, filter, fcu, ANIMTYPE_FCURVE);
+ }
+ else {
+ /* Just blindly isolate... This isn't the best, and shouldn't happen, but may be enough... */
+ fcu->flag |= (FCURVE_ACTIVE | FCURVE_SELECTED);
+ }
+ }
+ }
- /* api callbacks */
- ot->exec = screen_new_exec;
- ot->poll = WM_operator_winactive;
+ return OPERATOR_FINISHED;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Failed to open window!");
+ return OPERATOR_CANCELLED;
+ }
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Delete Screen Operator
- * \{ */
-
-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);
-
- return OPERATOR_FINISHED;
-}
-static void SCREEN_OT_delete(wmOperatorType *ot)
+static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Screen";
- ot->description = "Delete active screen";
- ot->idname = "SCREEN_OT_delete";
+ ot->name = "Show Drivers Editor";
+ ot->description = "Show drivers editor in a separate window";
+ ot->idname = "SCREEN_OT_drivers_editor_show";
/* api callbacks */
- ot->exec = screen_delete_exec;
+ ot->invoke = drivers_editor_show_invoke;
+ ot->poll = ED_operator_screenactive;
}
/** \} */
/* -------------------------------------------------------------------- */
-/** \name New Scene Operator
+/** \name New Screen Operator
* \{ */
-static int scene_new_exec(bContext *C, wmOperator *op)
+static int screen_new_exec(bContext *C, wmOperator *UNUSED(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);
+ wmWindow *win = CTX_wm_window(C);
+ WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook);
+ WorkSpaceLayout *layout_old = BKE_workspace_active_layout_get(win->workspace_hook);
+ WorkSpaceLayout *layout_new;
- WM_event_add_notifier(C, NC_SCENE | ND_SCENEBROWSE, newscene);
+ layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTBROWSE, layout_new);
return OPERATOR_FINISHED;
}
-static void SCENE_OT_new(wmOperatorType *ot)
+static void SCREEN_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";
+ ot->name = "New Screen";
+ ot->description = "Add a new screen";
+ ot->idname = "SCREEN_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", "");
+ ot->exec = screen_new_exec;
+ ot->poll = WM_operator_winactive;
}
/** \} */
@@ -4197,34 +4356,26 @@ static void SCENE_OT_new(wmOperatorType *ot)
/** \name Delete Screen Operator
* \{ */
-static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
+static int screen_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);
+ bScreen *sc = CTX_wm_screen(C);
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ WorkSpaceLayout *layout = BKE_workspace_layout_find(workspace, sc);
- WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene);
+ WM_event_add_notifier(C, NC_SCREEN | ND_LAYOUTDELETE, layout);
return OPERATOR_FINISHED;
}
-static void SCENE_OT_delete(wmOperatorType *ot)
+static void SCREEN_OT_delete(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Delete Scene";
- ot->description = "Delete active scene";
- ot->idname = "SCENE_OT_delete";
+ ot->name = "Delete Screen";
+ ot->description = "Delete active screen";
+ ot->idname = "SCREEN_OT_delete";
/* api callbacks */
- ot->exec = scene_delete_exec;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ ot->exec = screen_delete_exec;
}
/** \} */
@@ -4246,7 +4397,7 @@ typedef struct RegionAlphaInfo {
#define TIMEOUT 0.2f
#define TIMESTEP 0.04f
-float ED_region_blend_factor(ARegion *ar)
+float ED_region_blend_alpha(ARegion *ar)
{
/* check parent too */
if (ar->regiontimer == NULL && (ar->alignment & RGN_SPLIT_PREV) && ar->prev) {
@@ -4432,11 +4583,10 @@ static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent
PointerRNA ptr;
PropertyRNA *prop;
context_cycle_prop_get(CTX_wm_screen(C), CTX_wm_area(C), &ptr, &prop);
-
const int old_context = RNA_property_enum_get(&ptr, prop);
const int new_context = RNA_property_enum_step(
- C, &ptr, prop, old_context,
- direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
+ C, &ptr, prop, old_context,
+ direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
RNA_property_enum_set(&ptr, prop, new_context);
RNA_property_update(C, &ptr, prop);
@@ -4463,6 +4613,51 @@ static void SCREEN_OT_space_context_cycle(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Workspace Cycle Operator
+ * \{ */
+
+static int space_workspace_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ if (WM_window_is_temp_screen(win)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ Main *bmain = CTX_data_main(C);
+ const int direction = RNA_enum_get(op->ptr, "direction");
+ WorkSpace *workspace_src = WM_window_get_active_workspace(win);
+ WorkSpace *workspace_dst = (direction == SPACE_CONTEXT_CYCLE_PREV) ? workspace_src->id.prev : workspace_src->id.next;
+ if (workspace_dst == NULL) {
+ workspace_dst = (direction == SPACE_CONTEXT_CYCLE_PREV) ? bmain->workspaces.last : bmain->workspaces.first;
+ }
+ if (workspace_src != workspace_dst) {
+ win->workspace_hook->temp_workspace_store = workspace_dst;
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, workspace_dst);
+ win->workspace_hook->temp_workspace_store = NULL;
+ }
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_workspace_cycle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cycle Workspace";
+ ot->description = "Cycle through workspaces";
+ ot->idname = "SCREEN_OT_workspace_cycle";
+
+ /* api callbacks */
+ ot->invoke = space_workspace_cycle_invoke;
+ ot->poll = ED_operator_screenactive;;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "direction", space_context_cycle_direction, SPACE_CONTEXT_CYCLE_NEXT, "Direction",
+ "Direction to cycle through");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Assigning Operator Types
* \{ */
@@ -4495,8 +4690,10 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_screenshot);
WM_operatortype_append(SCREEN_OT_screencast);
WM_operatortype_append(SCREEN_OT_userpref_show);
+ WM_operatortype_append(SCREEN_OT_drivers_editor_show);
WM_operatortype_append(SCREEN_OT_region_blend);
WM_operatortype_append(SCREEN_OT_space_context_cycle);
+ WM_operatortype_append(SCREEN_OT_workspace_cycle);
/*frame changes*/
WM_operatortype_append(SCREEN_OT_frame_offset);
@@ -4511,8 +4708,6 @@ void ED_operatortypes_screen(void)
/* 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);
@@ -4618,10 +4813,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
- WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
- WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
- kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", F10KEY, KM_PRESS, KM_ALT, 0);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "use_hide_panels", true);
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
@@ -4632,9 +4825,14 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "SCREEN_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_PREV);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_workspace_cycle", TABKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_NEXT);
+ kmi = WM_keymap_add_item(keymap, "SCREEN_OT_workspace_cycle", TABKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_PREV);
+
/* tests */
WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
+ WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", RKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c
new file mode 100644
index 00000000000..d942602c896
--- /dev/null
+++ b/source/blender/editors/screen/screen_user_menu.c
@@ -0,0 +1,164 @@
+/*
+ * ***** 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.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ *
+ * Contributor(s): Blender Foundation
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/screen/screen_user_menu.c
+ * \ingroup spview3d
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "BLT_translation.h"
+
+#include "BKE_blender_user_menu.h"
+#include "BKE_context.h"
+#include "BKE_screen.h"
+#include "BKE_idprop.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Type
+ * \{ */
+
+bUserMenu *ED_screen_user_menu_find(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *context = CTX_data_mode_string(C);
+ return BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context);
+}
+
+bUserMenu *ED_screen_user_menu_ensure(bContext *C)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *context = CTX_data_mode_string(C);
+ return BKE_blender_user_menu_ensure(&U.user_menus, sl->spacetype, context);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Item
+ * \{ */
+
+bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(
+ ListBase *lb,
+ wmOperatorType *ot, IDProperty *prop, short opcontext)
+{
+ for (bUserMenuItem *umi = lb->first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ if (STREQ(ot->idname, umi_op->opname) &&
+ (opcontext == umi_op->opcontext) &&
+ (IDP_EqualsProperties(prop, umi_op->prop)))
+ {
+ return umi_op;
+ }
+ }
+ }
+ return NULL;
+}
+
+void ED_screen_user_menu_item_add_operator(
+ ListBase *lb, const char *ui_name,
+ wmOperatorType *ot, IDProperty *prop, short opcontext)
+{
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add(lb, USER_MENU_TYPE_OPERATOR);
+ umi_op->opcontext = opcontext;
+ if (!STREQ(ui_name, ot->name)) {
+ BLI_strncpy(umi_op->item.ui_name, ui_name, OP_MAX_TYPENAME);
+ }
+ BLI_strncpy(umi_op->opname, ot->idname, OP_MAX_TYPENAME);
+ umi_op->prop = prop ? IDP_CopyProperty(prop) : NULL;
+}
+
+void ED_screen_user_menu_item_remove(ListBase *lb, bUserMenuItem *umi)
+{
+ BLI_remlink(lb, umi);
+ BKE_blender_user_menu_item_free(umi);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Menu Definition
+ * \{ */
+
+static void screen_user_menu_draw(const bContext *C, Menu *menu)
+{
+ SpaceLink *sl = CTX_wm_space_data(C);
+ const char *context = CTX_data_mode_string(C);
+ bUserMenu *um_array[] = {
+ BKE_blender_user_menu_find(&U.user_menus, sl->spacetype, context),
+ (sl->spacetype != SPACE_TOPBAR) ? BKE_blender_user_menu_find(&U.user_menus, SPACE_TOPBAR, context) : NULL,
+ };
+ for (int um_index = 0; um_index < ARRAY_SIZE(um_array); um_index++) {
+ bUserMenu *um = um_array[um_index];
+ if (um == NULL) {
+ continue;
+ }
+ for (bUserMenuItem *umi = um->items.first; umi; umi = umi->next) {
+ if (umi->type == USER_MENU_TYPE_OPERATOR) {
+ bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)umi;
+ IDProperty *prop = umi_op->prop ? IDP_CopyProperty(umi_op->prop) : NULL;
+ uiItemFullO(
+ menu->layout, umi_op->opname, umi->ui_name[0] ? umi->ui_name : NULL,
+ ICON_NONE, prop, umi_op->opcontext, 0, NULL);
+ }
+ else if (umi->type == USER_MENU_TYPE_SEP) {
+ uiItemS(menu->layout);
+ }
+ }
+ }
+}
+
+void ED_screen_user_menu_register(void)
+{
+ MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
+ strcpy(mt->idname, "SCREEN_MT_user_menu");
+ strcpy(mt->label, "Quick Favorites");
+ strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
+ mt->draw = screen_user_menu_draw;
+ WM_menutype_add(mt);
+}
+
+/** \} */
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 54ff3d51479..e7b075dd5d0 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"
@@ -273,7 +275,7 @@ static void screenshot_draw(bContext *UNUSED(C), wmOperator *op)
/* main draw call */
RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr);
- uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, '\0');
+ uiDefAutoButsRNA(layout, &ptr, screenshot_draw_check_prop, UI_BUT_LABEL_ALIGN_NONE, false);
}
static int screenshot_poll(bContext *C)
@@ -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))
{
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
- glPushMatrix();
+ Gwn_VertFormat *format = immVertexFormat();
+ unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- glTranslatef((float)x, (float)y, 0.0f);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(0, 0, 0, 32);
+ imm_draw_circle_fill_2d(pos, (float)x, (float)y, 20, 40);
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_BLEND);
-
- glColor4ub(0, 0, 0, 32);
- glutil_draw_filled_arc(0.0, M_PI * 2.0, 20, 40);
+ immUniformColor4ub(255, 255, 255, 128);
+ imm_draw_circle_wire_2d(pos, (float)x, (float)y, 20, 40);
- glColor4ub(255, 255, 255, 128);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, 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..a044a7d377a
--- /dev/null
+++ b/source/blender/editors/screen/workspace_edit.c
@@ -0,0 +1,508 @@
+/*
+ * ***** 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 "RNA_define.h"
+
+#include "DEG_depsgraph.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_toolsystem.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)
+{
+ WorkSpace *workspace = BKE_workspace_add(bmain, name);
+
+ BKE_workspace_view_layer_set(workspace, act_view_layer, scene);
+
+ 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_exists(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(
+ Main *bmain, 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(bmain, 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(bmain, 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_exists(workspace_new, CTX_data_scene(C)) != NULL);
+ BLI_assert(CTX_wm_workspace(C) == workspace_new);
+
+ WM_toolsystem_unlink_all(C, workspace_old);
+ WM_toolsystem_reinit_all(C, win);
+
+ 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));
+
+ /* TODO(campbell): tools */
+
+ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) {
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, 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))
+{
+ wmWindow *win = CTX_wm_window(C);
+
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_DELETE, WM_window_get_active_workspace(win));
+
+ 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 int workspace_append_activate_poll(bContext *C)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
+ return WM_operator_poll(C, ot);
+}
+
+static int workspace_append(bContext *C, const char *directory, const char *idname)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_append", false);
+ PointerRNA opptr;
+ int retval;
+
+ WM_operator_properties_create_ptr(&opptr, ot);
+ RNA_string_set(&opptr, "directory", directory);
+ RNA_string_set(&opptr, "filename", idname);
+ RNA_boolean_set(&opptr, "autoselect", false);
+
+ retval = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &opptr);
+
+ WM_operator_properties_free(&opptr);
+
+ return retval;
+}
+
+static int workspace_append_activate_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ char idname[MAX_ID_NAME - 2], directory[FILE_MAX];
+
+ if (!RNA_struct_property_is_set(op->ptr, "idname") ||
+ !RNA_struct_property_is_set(op->ptr, "directory"))
+ {
+ return OPERATOR_CANCELLED;
+ }
+ RNA_string_get(op->ptr, "idname", idname);
+ RNA_string_get(op->ptr, "directory", directory);
+
+ if (workspace_append(C, directory, idname) != OPERATOR_CANCELLED) {
+ WorkSpace *appended_workspace = BLI_findstring(&bmain->workspaces, idname, offsetof(ID, name) + 2);
+
+ BLI_assert(appended_workspace != NULL);
+ /* Changing workspace changes context. Do delayed! */
+ WM_event_add_notifier(C, NC_SCREEN | ND_WORKSPACE_SET, appended_workspace);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+static void WORKSPACE_OT_append_activate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Append and Activate Workspace";
+ ot->description = "Append a workspace and make it the active one in the current window";
+ ot->idname = "WORKSPACE_OT_append_activate";
+
+ /* api callbacks */
+ ot->exec = workspace_append_activate_exec;
+ ot->poll = workspace_append_activate_poll;
+
+ RNA_def_string(ot->srna, "idname", NULL, MAX_ID_NAME - 2, "Identifier",
+ "Name of the workspace to append and activate");
+ RNA_def_string(ot->srna, "directory", NULL, FILE_MAX, "Directory",
+ "Path to the library");
+}
+
+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, "WORKSPACE_OT_append_activate"));
+ uiItemFullO_ptr(
+ layout, ot_append, workspace->id.name + 2, ICON_NONE, NULL,
+ WM_OP_EXEC_DEFAULT, 0, &opptr);
+ RNA_string_set(&opptr, "idname", id->name + 2);
+ RNA_string_set(&opptr, "directory", lib_path);
+}
+
+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("WORKSPACE_OT_append_activate", 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);
+ WM_operatortype_append(WORKSPACE_OT_append_activate);
+}
+
+/** \} 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..6d504c05dd1
--- /dev/null
+++ b/source/blender/editors/screen/workspace_layout_edit.c
@@ -0,0 +1,199 @@
+/*
+ * ***** 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(
+ Main *bmain,
+ WorkSpace *workspace,
+ wmWindow *win,
+ const char *name)
+{
+ bScreen *screen;
+ rcti screen_rect;
+
+ WM_window_screen_rect_calc(win, &screen_rect);
+ screen = screen_add(bmain, name, &screen_rect);
+
+ return BKE_workspace_layout_add(bmain, workspace, screen, name);
+}
+
+WorkSpaceLayout *ED_workspace_layout_duplicate(
+ Main *bmain,
+ 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(bmain, 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;
+}