Merge branch 'master' into blender2.8
[blender.git] / source / blender / editors / screen / screen_ops.c
index b3e788a..e504a11 100644 (file)
@@ -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"
 #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"
 #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);
+}
+
 /** \} */
 
 /* -------------------------------------------------------------------- */
@@ -714,9 +718,62 @@ AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2])
                                }
 
                                /* XXX force redraw to show/hide the action zone */
-                               ED_area_tag_redraw(sa);
+                               ED_area_tag_redraw_no_rebuild(sa);
                                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]);
+                               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! */
+                       }
                }
        }
 
@@ -779,6 +836,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);
@@ -790,11 +850,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:
@@ -815,10 +872,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 = ((is_in_area_actionzone(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;
@@ -1007,13 +1069,17 @@ static void SCREEN_OT_area_swap(wmOperatorType *ot)
 /* operator callback */
 static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
-       wmWindow *newwin, *win;
-       bScreen *newsc, *sc;
+       wmWindow *newwin, *win = CTX_wm_window(C);
+       Scene *scene;
+       WorkSpace *workspace = WM_window_get_active_workspace(win);
+       WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+       WorkSpaceLayout *layout_new;
+       bScreen *newsc;
        ScrArea *sa;
        rcti rect;
 
        win = CTX_wm_window(C);
-       sc = CTX_wm_screen(C);
+       scene = CTX_data_scene(C);
        sa = CTX_wm_area(C);
 
        /* XXX hrmf! */
@@ -1040,9 +1106,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(newwin, CTX_data_scene(C), sc->id.name + 2);
-       newwin->screen = newsc;
+       layout_new = ED_workspace_layout_add(workspace, newwin, BKE_workspace_layout_name_get(layout_old));
+       newsc = BKE_workspace_layout_screen_get(layout_new);
+       WM_window_set_active_layout(newwin, workspace, layout_new);
 
        /* copy area to new screen */
        ED_area_data_copy((ScrArea *)newsc->areabase.first, sa, true);
@@ -1110,32 +1180,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;
@@ -1150,9 +1270,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;
@@ -1174,9 +1294,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 */
@@ -1184,7 +1302,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");
@@ -1194,42 +1312,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;
 
-                       for (const ScrVert *v2 = sc->vertbase.first; v2; v2 = v2->next) {
-                               if (!v2->editflag) {
+               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 *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. */
@@ -1243,7 +1386,10 @@ static int area_snap_calc_location(
                                        }
                                }
                        }
+                       break;
                }
+               case SNAP_NONE:
+                       break;
        }
 
        return final_loc;
@@ -1254,29 +1400,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;
@@ -1291,12 +1434,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);
        }
 }
 
@@ -1305,7 +1462,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)
@@ -1315,8 +1472,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)
@@ -1384,10 +1541,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;
@@ -1506,7 +1668,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 */
@@ -1524,8 +1686,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;
 }
@@ -1544,16 +1712,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;
@@ -1592,6 +1760,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;
        }
@@ -1617,8 +1787,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)
@@ -1634,14 +1804,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;
 
@@ -1688,7 +1859,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;
 
@@ -1708,7 +1879,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);
@@ -1826,10 +1997,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) {
@@ -1841,19 +2013,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;
@@ -1862,7 +2035,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;
@@ -2031,7 +2204,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;
@@ -2075,7 +2249,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 * 3) / 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;
@@ -2084,6 +2260,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) {
@@ -2103,6 +2286,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
@@ -2122,7 +2312,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) {
 
@@ -2185,16 +2375,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);
@@ -2505,64 +2694,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;
 }
 
@@ -2618,6 +2759,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;
@@ -2627,7 +2777,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");
@@ -2760,9 +2910,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)
@@ -2931,16 +3081,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;
 
@@ -3344,6 +3494,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)
 {
@@ -3354,7 +3516,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;
 }
 
@@ -3437,6 +3599,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);
 
@@ -3447,12 +3611,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");
        }
 }
 
@@ -3512,13 +3675,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;
@@ -3569,7 +3733,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) {
@@ -3599,6 +3763,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);
@@ -3709,10 +3874,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;
@@ -3728,7 +3895,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);
@@ -3792,11 +3959,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;
                }
        }
 
@@ -3805,11 +3972,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;
                }
        }
 
@@ -3831,7 +3998,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);
@@ -4033,7 +4200,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) {
@@ -4061,117 +4228,100 @@ 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)
 {
-       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(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(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;
 }
 
 /** \} */
@@ -4180,34 +4330,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;
 }
 
 /** \} */
@@ -4229,7 +4371,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) {
@@ -4415,11 +4557,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);
 
@@ -4445,6 +4586,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
  * \{ */
@@ -4478,8 +4664,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);
@@ -4494,8 +4682,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);
@@ -4601,10 +4787,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);
@@ -4615,6 +4799,11 @@ 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);