UI: Global "Status-bar" Area (WIP)
authorJulian Eisel <eiseljulian@gmail.com>
Wed, 23 May 2018 20:38:25 +0000 (22:38 +0200)
committerJulian Eisel <eiseljulian@gmail.com>
Wed, 23 May 2018 20:38:25 +0000 (22:38 +0200)
* Add horizontal bar at bottom of all non-temp windows, similar to the Top-bar.
* Status-bar is hidden in UI-less fullscreen mode
* Current contents are preliminary and based on T54861:
** Left: Current file-path if needed. "(Modified)" note if file was changed.
** Center: Scene statistics (like in 2.7 Info Editor).
** Right: Progress-bars and reports
* Internally managed as own "STATUSBAR" editor-type (hidden in UI).
* Like with the Top-bar, Status-bar data and SDNA writing is disabled.
* Most changes in low-level screen/area code are to support layout bounds that differ from window bounds.

Design task: T54861
Main changes approved by @brecht.

22 files changed:
build_files/cmake/macros.cmake
release/scripts/startup/bl_ui/__init__.py
release/scripts/startup/bl_ui/space_statusbar.py [new file with mode: 0644]
release/scripts/startup/bl_ui/space_topbar.py
source/blender/blenloader/intern/writefile.c
source/blender/editors/CMakeLists.txt
source/blender/editors/include/ED_screen.h
source/blender/editors/include/ED_space_api.h
source/blender/editors/screen/area.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/screen/screen_intern.h
source/blender/editors/screen/screen_ops.c
source/blender/editors/screen/workspace_layout_edit.c
source/blender/editors/space_api/spacetypes.c
source/blender/editors/space_statusbar/CMakeLists.txt [new file with mode: 0644]
source/blender/editors/space_statusbar/space_statusbar.c [new file with mode: 0644]
source/blender/makesdna/DNA_screen_types.h
source/blender/makesdna/DNA_space_types.h
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_space.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_window.c

index 3bb435fa89221bf71c95ba42f46a2b793c1d57ce..a38a6805274d67589849a7057971fbeec7a6a908 100644 (file)
@@ -581,6 +581,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
                bf_editor_space_outliner
                bf_editor_space_script
                bf_editor_space_sequencer
+               bf_editor_space_statusbar
                bf_editor_space_text
                bf_editor_space_time
                bf_editor_space_topbar
index 0de0e8ad72d9384c574217a499c1ec3d3ca5b5cb..dd99195f12a0a0440687762420e5d5cd7b8aba3e 100644 (file)
@@ -81,6 +81,7 @@ _modules = [
     "space_outliner",
     "space_properties",
     "space_sequencer",
+    "space_statusbar",
     "space_text",
     "space_time",
     "space_topbar",
diff --git a/release/scripts/startup/bl_ui/space_statusbar.py b/release/scripts/startup/bl_ui/space_statusbar.py
new file mode 100644 (file)
index 0000000..983b474
--- /dev/null
@@ -0,0 +1,84 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+import bpy
+from bpy.types import Header
+
+
+class STATUSBAR_HT_header(Header):
+    bl_space_type = 'STATUSBAR'
+
+    def draw(self, context):
+        area = context.area
+        region = context.region
+
+        if region.alignment == 'RIGHT':
+            if region == area.regions[0]:
+                self.draw_right(context)
+            else:
+                self.draw_center(context)
+        else:
+            self.draw_left(context)
+
+    def draw_left(self, context):
+        layout = self.layout
+
+        row = layout.row(align=True)
+        if (bpy.data.filepath):
+            row.label(text=bpy.data.filepath, translate=False)
+        if bpy.data.is_dirty:
+            row.label("(Modified)")
+
+    def draw_center(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        view_layer = context.view_layer
+
+        layout.label(text=scene.statistics(view_layer), translate=False)
+
+    def draw_right(self, context):
+        layout = self.layout
+
+        layout.template_running_jobs()
+        layout.template_reports_banner()
+
+        row = layout.row(align=True)
+        if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False:
+            row.label("Auto-run disabled", icon='ERROR')
+            if bpy.data.is_saved:
+                props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted")
+                props.use_scripts = True
+
+            row.operator("script.autoexec_warn_clear", text="Ignore")
+
+            # include last so text doesn't push buttons out of the header
+            row.label(bpy.app.autoexec_fail_message)
+            return
+
+
+
+classes = (
+    STATUSBAR_HT_header,
+)
+
+if __name__ == "__main__":  # only for live edit.
+    from bpy.utils import register_class
+    for cls in classes:
+        register_class(cls)
index 1c4e5493e2489f7bc316718e757749b66d4c37c6..4eabf2bf327cf466ad034733608358af506ba96e 100644 (file)
@@ -57,26 +57,6 @@ class TOPBAR_HT_upper_bar(Header):
                 text="Back to Previous",
             )
 
-        layout.separator()
-
-        layout.template_running_jobs()
-
-        layout.template_reports_banner()
-
-        row = layout.row(align=True)
-
-        if bpy.app.autoexec_fail is True and bpy.app.autoexec_fail_quiet is False:
-            row.label("Auto-run disabled", icon='ERROR')
-            if bpy.data.is_saved:
-                props = row.operator("wm.revert_mainfile", icon='SCREEN_BACK', text="Reload Trusted")
-                props.use_scripts = True
-
-            row.operator("script.autoexec_warn_clear", text="Ignore")
-
-            # include last so text doesn't push buttons out of the header
-            row.label(bpy.app.autoexec_fail_message)
-            return
-
     def draw_right(self, context):
         layout = self.layout
 
index d94fe790c9ddcbfe902887ad200bcfeab3f5e622..f3042dc84db7d1cae274298638374298e23a4fe8 100644 (file)
@@ -2879,10 +2879,13 @@ static void write_area_regions(WriteData *wd, ScrArea *area)
                        }
                        writestruct(wd, DATA, SpaceConsole, 1, sl);
                }
-#ifdef WITH_TOPBAR_WRITING
+#ifdef WITH_GLOBAL_AREA_WRITING
                else if (sl->spacetype == SPACE_TOPBAR) {
                        writestruct(wd, DATA, SpaceTopBar, 1, sl);
                }
+               else if (sl->spacetype == SPACE_STATUSBAR) {
+                       writestruct(wd, DATA, SpaceStatusBar, 1, sl);
+               }
 #endif
                else if (sl->spacetype == SPACE_USERPREF) {
                        writestruct(wd, DATA, SpaceUserPref, 1, sl);
@@ -2905,7 +2908,7 @@ static void write_area_map(WriteData *wd, ScrAreaMap *area_map)
 
                writestruct(wd, DATA, ScrArea, 1, area);
 
-#ifdef WITH_TOPBAR_WRITING
+#ifdef WITH_GLOBAL_AREA_WRITING
                writestruct(wd, DATA, ScrGlobalAreaData, 1, area->global);
 #endif
 
@@ -2921,7 +2924,7 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
        write_iddata(wd, &wm->id);
 
        for (wmWindow *win = wm->windows.first; win; win = win->next) {
-#ifndef WITH_TOPBAR_WRITING
+#ifndef WITH_GLOBAL_AREA_WRITING
                /* Don't write global areas yet, while we make changes to them. */
                ScrAreaMap global_areas = win->global_areas;
                memset(&win->global_areas, 0, sizeof(win->global_areas));
@@ -2934,7 +2937,7 @@ static void write_windowmanager(WriteData *wd, wmWindowManager *wm)
                writestruct(wd, DATA, WorkSpaceInstanceHook, 1, win->workspace_hook);
                writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format);
 
-#ifdef WITH_TOPBAR_WRITING
+#ifdef WITH_GLOBAL_AREA_WRITING
                write_area_map(wd, &win->global_areas);
 #else
                win->global_areas = global_areas;
index 358f82499c21790772b9b1f9e810e40550dbd554..2b30382f4a4773201e3f8d4228f188031f9f7250 100644 (file)
@@ -54,6 +54,7 @@ if(WITH_BLENDER)
        add_subdirectory(space_outliner)
        add_subdirectory(space_script)
        add_subdirectory(space_sequencer)
+       add_subdirectory(space_statusbar)
        add_subdirectory(space_text)
        add_subdirectory(space_topbar)
        add_subdirectory(space_userpref)
index c30aaf8df0ad67ebc8a0e312f5270c34ca899112..749d1347eb346263deb974ba25cf40538db57f96 100644 (file)
@@ -119,9 +119,6 @@ int     ED_area_header_switchbutton(const struct bContext *C, struct uiBlock *bl
 void    ED_area_initialize(struct wmWindowManager *wm, struct wmWindow *win, struct ScrArea *sa);
 void    ED_area_exit(struct bContext *C, struct ScrArea *sa);
 int     ED_screen_area_active(const struct bContext *C);
-void    ED_screen_global_topbar_area_create(
-            struct wmWindow *win,
-            const struct bScreen *screen);
 void    ED_screen_global_areas_create(
             struct wmWindow *win);
 void    ED_area_do_listen(struct bScreen *sc, ScrArea *sa, struct wmNotifier *note, Scene *scene,
index 0cb235148678440bd99c2726b233be7fb3af4bb7..77539bff252d73732e6d903b9c8a5b7345e93d7c 100644 (file)
@@ -57,6 +57,7 @@ void ED_spacetype_logic(void);
 void ED_spacetype_console(void);
 void ED_spacetype_userpref(void);
 void ED_spacetype_clip(void);
+void ED_spacetype_statusbar(void);
 void ED_spacetype_topbar(void);
 
 /* calls for instancing and freeing spacetype static data 
index dc5c9be04c8b66ca63bfbdddb8d33ad6117c15e8..e8192c4ce90a60c12c059a738c4d82d381fff241 100644 (file)
@@ -1259,7 +1259,7 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
        region_rect_recursive(win, sa, ar->next, remainder, overlap_remainder, quad);
 }
 
-static void area_calc_totrct(ScrArea *sa, int window_size_x, int window_size_y)
+static void area_calc_totrct(ScrArea *sa, const rcti *window_rect)
 {
        short px = (short)U.pixelsize;
 
@@ -1269,16 +1269,16 @@ static void area_calc_totrct(ScrArea *sa, int window_size_x, int window_size_y)
        sa->totrct.ymax = sa->v2->vec.y;
 
        /* scale down totrct by 1 pixel on all sides not matching window borders */
-       if (sa->totrct.xmin > 0) {
+       if (sa->totrct.xmin > window_rect->xmin) {
                sa->totrct.xmin += px;
        }
-       if (sa->totrct.xmax < (window_size_x - 1)) {
+       if (sa->totrct.xmax < (window_rect->xmax - 1)) {
                sa->totrct.xmax -= px;
        }
-       if (sa->totrct.ymin > 0) {
+       if (sa->totrct.ymin > window_rect->ymin) {
                sa->totrct.ymin += px;
        }
-       if (sa->totrct.ymax < (window_size_y - 1)) {
+       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.
@@ -1373,15 +1373,15 @@ 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;
        }
 
-       const int size_x = WM_window_pixels_x(win);
-       const int size_y = WM_window_pixels_y(win);
-       rcti rect, overlap_rect;
-
-       area_calc_totrct(area, size_x, size_y);
+       WM_window_rect_calc(win, &window_rect);
+       area_calc_totrct(area, &window_rect);
 
        /* region rect sizes */
        rect = area->totrct;
@@ -1406,15 +1406,14 @@ 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);
-
-       const int window_size_x = WM_window_pixels_x(win);
-       const int window_size_y = WM_window_pixels_y(win);
        ARegion *ar;
        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);
@@ -1428,7 +1427,7 @@ void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
                ar->type = BKE_regiontype_from_id(sa->type, ar->regiontype);
 
        /* area sizes */
-       area_calc_totrct(sa, window_size_x, window_size_y);
+       area_calc_totrct(sa, &window_rect);
 
        /* region rect sizes */
        rect = sa->totrct;
index 4208f3f6233b166ddb9a18e766e4aab01f3b9d76..c7578741d24c36e1f90547906b5cb1801ffc9b15 100644 (file)
@@ -111,10 +111,12 @@ 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 */
+/**
+ * \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 int winsize_x, const int winsize_y,
+        const rcti *bounds_rect,
         const int mx, const int my)
 {
        int safety = U.widget_unit / 10;
@@ -123,7 +125,7 @@ ScrEdge *screen_area_map_find_active_scredge(
 
        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);
@@ -133,7 +135,7 @@ ScrEdge *screen_area_map_find_active_scredge(
                        }
                }
                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);
@@ -153,13 +155,17 @@ ScrEdge *screen_find_active_scredge(
         const int mx, const int my)
 {
        /* Use layout size (screen excluding global areas) for screen-layout area edges */
-       const int screen_x = WM_window_screen_pixels_x(win), screen_y = WM_window_screen_pixels_y(win);
-       ScrEdge *se = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(screen), screen_x, screen_y, mx, my);
+       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 */
-               const int win_x = WM_window_pixels_x(win), win_y = WM_window_pixels_y(win);
-               se = screen_area_map_find_active_scredge(&win->global_areas, win_x, win_y, mx, my);
+               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;
 }
@@ -334,7 +340,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
 /**
  * Empty screen, with 1 dummy area without spacedata. Uses window size.
  */
-bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y)
+bScreen *screen_add(const char *name, const rcti *rect)
 {
        bScreen *sc;
        ScrVert *sv1, *sv2, *sv3, *sv4;
@@ -343,10 +349,10 @@ bScreen *screen_add(const char *name, const int winsize_x, const int winsize_y)
        sc->do_refresh = true;
        sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN;
 
-       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);
@@ -546,34 +552,29 @@ void select_connected_scredge(const wmWindow *win, ScrEdge *edge)
  */
 static void screen_vertices_scale(
         const wmWindow *win, bScreen *sc,
-        int window_size_x, int window_size_y,
-        int screen_size_x, int screen_size_y)
+        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 screen_size_x_prev, screen_size_y_prev;
-       float facx, facy, tempf, min[2], max[2];
-       
+       float min[2], max[2];
+
        /* calculate size */
        min[0] = min[1] = 20000.0f;
        max[0] = max[1] = 0.0f;
-       
+
        for (sv = sc->vertbase.first; sv; sv = sv->next) {
                const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y};
                minmax_v2v2_v2(min, max, fv);
        }
-       
-       /* always make 0.0 left under */
-       for (sv = sc->vertbase.first; sv; sv = sv->next) {
-               sv->vec.x -= min[0];
-               sv->vec.y -= min[1];
-       }
-       
+
        screen_size_x_prev = (max[0] - min[0]) + 1;
        screen_size_y_prev = (max[1] - min[1]) + 1;
 
@@ -590,12 +591,12 @@ static void screen_vertices_scale(
                        sa->temp = 0;
 
                        if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) {
-                               if (sa->v2->vec.y == screen_size_y_prev) {
+                               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;
                                        }
@@ -607,26 +608,16 @@ static void screen_vertices_scale(
 
 
        if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) {
-               facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1);
-               facy = ((float)screen_size_y) / ((float)screen_size_y_prev);
-               
+               const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1);
+               const float facy = ((float)screen_size_y) / ((float)screen_size_y_prev);
+
                /* make sure it fits! */
                for (sv = sc->vertbase.first; sv; sv = sv->next) {
-                       /* FIXME, this re-sizing logic is no good when re-sizing the window + redrawing [#24428]
-                        * need some way to store these as floats internally and re-apply from there. */
-                       tempf = ((float)sv->vec.x) * facx;
-                       sv->vec.x = (short)(tempf + 0.5f);
-                       //sv->vec.x += AREAGRID - 1;
-                       //sv->vec.x -=  (sv->vec.x % AREAGRID);
-
-                       CLAMP(sv->vec.x, 0, screen_size_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);
+                       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.y, 0, screen_size_y);
+                       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);
                }
        }
 
@@ -688,23 +679,22 @@ static void screen_vertices_scale(
        /* make each window at least ED_area_headersize() high */
        for (sa = sc->areabase.first; sa; sa = sa->next) {
                int headery = headery_init;
-               
+
                /* adjust headery if verts are along the edge of window */
-               if (sa->v1->vec.y > 0)
+               if (sa->v1->vec.y > window_rect->ymin)
                        headery += U.pixelsize;
-               if (sa->v2->vec.y < screen_size_y)
+               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 = 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(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) {
@@ -717,18 +707,25 @@ static void screen_vertices_scale(
                }
        }
 
-       /* Global areas have a fixed size that only changes with the DPI. Here we ensure that exactly this size is set.
-        * TODO Assumes global area to be top-aligned. Should be made more generic */
+       /* 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 = 0;
-               area->v3->vec.x = area->v4->vec.x = window_size_x - 1;
+               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->v2->vec.y = area->v3->vec.y = window_size_y - 1;
-               area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - ED_area_global_size_y(area);
+               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;
+               }
        }
 }
 
@@ -802,18 +799,16 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
 
        /* exception for bg mode, we only need the screen context */
        if (!G.background) {
-               WM_window_set_dpi(win);
-
-               /* Get window pixels __after__ updating window DPI! */
-               const int window_size_x = WM_window_pixels_x(win);
-               const int window_size_y = WM_window_pixels_y(win);
-               const int screen_size_x = WM_window_screen_pixels_x(win);
-               const int screen_size_y = WM_window_screen_pixels_y(win);
+               rcti window_rect, screen_rect;
 
                /* header size depends on DPI, let's verify */
+               WM_window_set_dpi(win);
                screen_refresh_headersizes();
 
-               screen_vertices_scale(win, screen, window_size_x, window_size_y, screen_size_x, screen_size_y);
+               WM_window_rect_calc(win, &window_rect);
+               WM_window_screen_rect_calc(win, &screen_rect); /* Get screen bounds __after__ updating window DPI! */
+
+               screen_vertices_scale(win, screen, &window_rect, &screen_rect);
 
                ED_screen_areas_iter(win, screen, area) {
                        /* set spacetype and region callbacks, calls init() */
@@ -921,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);
        
@@ -933,13 +926,14 @@ void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
 
        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);
        }
-       for (sa = window->global_areas.areabase.first; sa; sa = sa->next) {
+       /* 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);
        }
 
@@ -1113,39 +1107,56 @@ static ScrArea *screen_area_create_with_geometry(
        return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype);
 }
 
-void ED_screen_global_topbar_area_create(wmWindow *win, const bScreen *screen)
+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)
 {
-       if (screen->temp == 0) {
-               const short size_y = 2.25 * HEADERY;
-               SpaceType *st;
-               SpaceLink *sl;
-               ScrArea *sa;
-               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;
-
-               sa = screen_area_create_with_geometry(&win->global_areas, &rect, SPACE_TOPBAR);
-               st = BKE_spacetype_from_id(SPACE_TOPBAR);
-               sl = st->new(sa, WM_window_get_active_scene(win));
-               sa->regionbase = sl->regionbase;
-
-               /* Data specific to global areas. */
-               sa->global = MEM_callocN(sizeof(*sa->global), __func__);
-               sa->global->cur_fixed_height = size_y;
-               sa->global->size_max = size_y;
-               sa->global->size_min = HEADERY;
-
-               BLI_addhead(&sa->spacedata, sl);
-               BLI_listbase_clear(&sl->regionbase);
-       }
-       /* Do not create more area types here! Function is called on file load (wm_window_ghostwindows_ensure). TODO */
+       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)
 {
-       const bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
-       ED_screen_global_topbar_area_create(win, screen);
+       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);
+       }
 }
 
 
index 045e5ee6b4802ca49c514644f727a9912438cc39..b54a5e0457140e1533b7b2e0e843f27751a33cef 100644 (file)
@@ -48,7 +48,7 @@ void        screen_area_update_region_sizes(wmWindowManager *wm, wmWindow *win,
 void        region_toggle_hidden(struct bContext *C, ARegion *ar, const bool do_fade);
 
 /* screen_edit.c */
-bScreen    *screen_add(const char *name, const int winsize_x, const int winsize_y);
+bScreen    *screen_add(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);
@@ -61,7 +61,7 @@ void        select_connected_scredge(const wmWindow *win, ScrEdge *edge);
 bool        scredge_is_horizontal(ScrEdge *se);
 ScrEdge     *screen_area_map_find_active_scredge(
         const struct ScrAreaMap *area_map,
-        const int winsize_x, const int winsize_y,
+        const rcti *bounds_rect,
         const int mx, const int my);
 ScrEdge    *screen_find_active_scredge(
         const wmWindow *win, const bScreen *screen,
index 0c13ac03d1b7d178d77efa2360c5a8a3d7d815d5..2063191658b0b0227050c8a96e0fc8ce0556a28d 100644 (file)
@@ -842,11 +842,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 screen_size_x = WM_window_screen_pixels_x(win);
-       const int screen_size_y = WM_window_screen_pixels_y(win);
 
        switch (event->type) {
                case MOUSEMOVE:
@@ -867,11 +864,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_area_map_find_active_scredge(
-                                                  AREAMAP_FROM_SCREEN(sc), screen_size_x, screen_size_y, event->x, event->y) == NULL));
+                                                  AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y) == NULL));
                        }
                        else {
                                const int delta_min = 1;
@@ -1186,10 +1187,10 @@ typedef struct sAreaMoveData {
 } sAreaMoveData;
 
 /* helper call to move area-edge, sets limits
- * need window size in order to get correct limits */
+ * need window bounds in order to get correct limits */
 static void area_move_set_limits(
         wmWindow *win, bScreen *sc, int dir,
-        const int winsize_x, const int winsize_y,
+        const rcti *screen_rect,
         int *bigger, int *smaller,
         bool *use_bigger_smaller_snap)
 {
@@ -1242,9 +1243,9 @@ static void area_move_set_limits(
                        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;
@@ -1259,9 +1260,9 @@ static void area_move_set_limits(
                        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;
@@ -1283,8 +1284,7 @@ static int area_move_init(bContext *C, wmOperator *op)
        wmWindow *win = CTX_wm_window(C);
        ScrEdge *actedge;
        sAreaMoveData *md;
-       const int screen_size_x = WM_window_screen_pixels_x(win);
-       const int screen_size_y = WM_window_screen_pixels_y(win);
+       rcti screen_rect;
        int x, y;
        
        /* required properties */
@@ -1308,8 +1308,10 @@ static int area_move_init(bContext *C, wmOperator *op)
                v1->editflag = v1->flag;
        }
 
+       WM_window_screen_rect_calc(win, &screen_rect);
+
        bool use_bigger_smaller_snap = false;
-       area_move_set_limits(win, sc, md->dir, screen_size_x, screen_size_y,
+       area_move_set_limits(win, sc, md->dir, &screen_rect,
                             &md->bigger, &md->smaller,
                             &use_bigger_smaller_snap);
 
@@ -1772,14 +1774,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 screen_size_x = WM_window_screen_pixels_x(win);
-       const int screen_size_y = WM_window_screen_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;
                
@@ -1825,8 +1828,8 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
                        y = RNA_int_get(op->ptr, "mouse_y");
                else
                        y = event->x;
-               
-               actedge = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), screen_size_x, screen_size_y, x, y);
+
+               actedge = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, x, y);
                if (actedge == NULL)
                        return OPERATOR_CANCELLED;
                
@@ -1846,8 +1849,8 @@ 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(win, sc, dir, screen_size_x, screen_size_y, &sd->bigger, &sd->smaller, NULL);
-                       
+                       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);
                        
@@ -2731,7 +2734,8 @@ 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) &&
-              ((screen->state != SCREENNORMAL) || (area->spacetype != SPACE_TOPBAR));
+               /* 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)
@@ -3047,17 +3051,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 screen_size_x = WM_window_screen_pixels_x(win);
-       const int screen_size_y = WM_window_screen_pixels_y(win);
+       rcti screen_rect;
 
-       actedge = screen_area_map_find_active_scredge(
-                     AREAMAP_FROM_SCREEN(sc), screen_size_x, screen_size_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;
        
index a6f991d4bbe285663be44ac31de612885f4cb8fa..6285f031836ca7b5f4c928a7bc5c5b973c422a79 100644 (file)
@@ -50,13 +50,13 @@ WorkSpaceLayout *ED_workspace_layout_add(
         wmWindow *win,
         const char *name)
 {
-       const int screen_size_x = WM_window_screen_pixels_x(win);
-       const int screen_size_y = WM_window_screen_pixels_y(win);
+       bScreen *screen;
+       rcti screen_rect;
 
-       bScreen *screen = screen_add(name, screen_size_x, screen_size_y);
-       WorkSpaceLayout *layout = BKE_workspace_layout_add(workspace, screen, name);
+       WM_window_screen_rect_calc(win, &screen_rect);
+       screen = screen_add(name, &screen_rect);
 
-       return layout;
+       return BKE_workspace_layout_add(workspace, screen, name);
 }
 
 WorkSpaceLayout *ED_workspace_layout_duplicate(
index 12f16f1fe42753fb42e47af5f8ac441920068153..4d4bcf4dffc130139abe43f2fa0e2fe651ddac3e 100644 (file)
@@ -97,9 +97,10 @@ void ED_spacetypes_init(void)
        ED_spacetype_console();
        ED_spacetype_userpref();
        ED_spacetype_clip();
+       ED_spacetype_statusbar();
        ED_spacetype_topbar();
 //     ...
-       
+
        /* register operator types for screen and all spaces */
        ED_operatortypes_workspace();
        ED_operatortypes_scene();
diff --git a/source/blender/editors/space_statusbar/CMakeLists.txt b/source/blender/editors/space_statusbar/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3143994
--- /dev/null
@@ -0,0 +1,45 @@
+# ***** 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.
+#
+# Contributor(s): Jacques Beaurain.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+       ../include
+       ../../blenkernel
+       ../../blenlib
+       ../../blenloader
+       ../../blentranslation
+       ../../gpu
+       ../../makesdna
+       ../../makesrna
+       ../../windowmanager
+       ../../../../intern/guardedalloc
+       ../../../../intern/glew-mx
+)
+
+set(INC_SYS
+       ${GLEW_INCLUDE_PATH}
+)
+
+set(SRC
+       space_statusbar.c
+)
+
+add_definitions(${GL_DEFINITIONS})
+
+blender_add_lib(bf_editor_space_statusbar "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_statusbar/space_statusbar.c b/source/blender/editors/space_statusbar/space_statusbar.c
new file mode 100644 (file)
index 0000000..4c6a2ee
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * ***** 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/space_statusbar/space_statusbar.c
+ *  \ingroup spstatusbar
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "BKE_context.h"
+#include "BKE_screen.h"
+
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "RNA_access.h"
+
+#include "UI_interface.h"
+#include "UI_view2d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+
+
+/* ******************** default callbacks for statusbar space ********************  */
+
+static SpaceLink *statusbar_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene))
+{
+       ARegion *ar;
+       SpaceStatusBar *sstatusbar;
+
+       sstatusbar = MEM_callocN(sizeof(*sstatusbar), "init statusbar");
+       sstatusbar->spacetype = SPACE_STATUSBAR;
+
+       /* header regions */
+       /* *** NOTE: ***
+        * Python layout code (space_statusbar.py) depends on the list order of
+        * these! Not nice at all, but the only way to identify the correct header
+        * to draw to is using alignment + list position. It can't use alignment
+        * only since code below has to set two right aligned regions - XXX. */
+       ar = MEM_callocN(sizeof(*ar), "right aligned header for statusbar");
+       BLI_addtail(&sstatusbar->regionbase, ar);
+       ar->regiontype = RGN_TYPE_HEADER;
+       ar->alignment = RGN_ALIGN_RIGHT;
+       ar = MEM_callocN(sizeof(*ar), "center header for statusbar");
+       BLI_addtail(&sstatusbar->regionbase, ar);
+       ar->regiontype = RGN_TYPE_HEADER;
+       ar->alignment = RGN_ALIGN_RIGHT; /* Right aligned too, so region layout code scales it correctly. */
+       ar = MEM_callocN(sizeof(*ar), "left aligned header for statusbar");
+       BLI_addtail(&sstatusbar->regionbase, ar);
+       ar->regiontype = RGN_TYPE_HEADER;
+       ar->alignment = RGN_ALIGN_NONE;
+
+       return (SpaceLink *)sstatusbar;
+}
+
+/* not spacelink itself */
+static void statusbar_free(SpaceLink *UNUSED(sl))
+{
+
+}
+
+
+/* spacetype; init callback */
+static void statusbar_init(struct wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa))
+{
+
+}
+
+static SpaceLink *statusbar_duplicate(SpaceLink *sl)
+{
+       SpaceStatusBar *sstatusbarn = MEM_dupallocN(sl);
+
+       /* clear or remove stuff from old */
+
+       return (SpaceLink *)sstatusbarn;
+}
+
+
+
+/* add handlers, stuff you only do once or on area/region changes */
+static void statusbar_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region)
+{
+       if (ELEM(region->alignment, RGN_ALIGN_RIGHT)) {
+               region->flag |= RGN_FLAG_DYNAMIC_SIZE;
+       }
+       ED_region_header_init(region);
+}
+
+static void statusbar_operatortypes(void)
+{
+
+}
+
+static void statusbar_keymap(struct wmKeyConfig *UNUSED(keyconf))
+{
+
+}
+
+static void statusbar_header_region_listener(
+        bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar,
+        wmNotifier *wmn, const Scene *UNUSED(scene))
+{
+       /* context changes */
+       switch (wmn->category) {
+               case NC_SCREEN:
+                       if (ELEM(wmn->data, ND_LAYER, ND_SCREENCAST, ND_ANIMPLAY)) {
+                               ED_region_tag_redraw(ar);
+                       }
+                       break;
+               case NC_WM:
+                       if (wmn->data == ND_JOB)
+                               ED_region_tag_redraw(ar);
+                       break;
+               case NC_SCENE:
+                       if (wmn->data == ND_RENDER_RESULT)
+                               ED_region_tag_redraw(ar);
+                       break;
+               case NC_SPACE:
+                       if (wmn->data == ND_SPACE_INFO)
+                               ED_region_tag_redraw(ar);
+                       break;
+               case NC_ID:
+                       if (wmn->action == NA_RENAME)
+                               ED_region_tag_redraw(ar);
+                       break;
+       }
+}
+
+static void statusbar_header_region_message_subscribe(
+        const bContext *UNUSED(C),
+        WorkSpace *UNUSED(workspace), Scene *UNUSED(scene),
+        bScreen *UNUSED(screen), ScrArea *UNUSED(sa), ARegion *ar,
+        struct wmMsgBus *mbus)
+{
+       wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+               .owner = ar,
+               .user_data = ar,
+               .notify = ED_region_do_msg_notify_tag_redraw,
+       };
+
+       WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw);
+       WM_msg_subscribe_rna_anon_prop(mbus, ViewLayer, name, &msg_sub_value_region_tag_redraw);
+}
+
+/* only called once, from space/spacetypes.c */
+void ED_spacetype_statusbar(void)
+{
+       SpaceType *st = MEM_callocN(sizeof(*st), "spacetype statusbar");
+       ARegionType *art;
+
+       st->spaceid = SPACE_STATUSBAR;
+       strncpy(st->name, "Status Bar", BKE_ST_MAXNAME);
+
+       st->new = statusbar_new;
+       st->free = statusbar_free;
+       st->init = statusbar_init;
+       st->duplicate = statusbar_duplicate;
+       st->operatortypes = statusbar_operatortypes;
+       st->keymap = statusbar_keymap;
+
+       /* regions: header window */
+       art = MEM_callocN(sizeof(*art), "spacetype statusbar header region");
+       art->regionid = RGN_TYPE_HEADER;
+       art->prefsizey = HEADERY;
+       art->prefsizex = UI_UNIT_X * 5; /* Mainly to avoid glitches */
+       art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER;
+       art->init = statusbar_header_region_init;
+       art->layout = ED_region_header_layout;
+       art->draw = ED_region_header_draw;
+       art->listener = statusbar_header_region_listener;
+       art->message_subscribe = statusbar_header_region_message_subscribe;
+       BLI_addhead(&st->regiontypes, art);
+
+       BKE_spacetype_register(st);
+}
index 1f14bb58e7861db72e73a7f8561610a0e4a9fdd9..ef0dbceef388c59dba134840de816a39982236b4 100644 (file)
@@ -227,7 +227,7 @@ typedef struct uiPreview {           /* some preview UI data need to be saved in
 } uiPreview;
 
 /* These two lines with # tell makesdna this struct can be excluded.
- * Should be: #ifndef WITH_TOPBAR_WRITING */
+ * Should be: #ifndef WITH_GLOBAL_AREA_WRITING */
 #
 #
 typedef struct ScrGlobalAreaData {
@@ -240,14 +240,21 @@ typedef struct ScrGlobalAreaData {
         * if they are 'collapsed' or not. Value is set on area creation and not
         * touched afterwards. */
        short size_min, size_max;
+       short align; /* GlobalAreaAlign */
 
        short flag; /* GlobalAreaFlag */
+       short pad;
 } ScrGlobalAreaData;
 
 enum GlobalAreaFlag {
        GLOBAL_AREA_IS_HIDDEN = (1 << 0),
 };
 
+typedef enum GlobalAreaAlign {
+       GLOBAL_AREA_ALIGN_TOP,
+       GLOBAL_AREA_ALIGN_BOTTOM,
+} GlobalAreaAlign;
+
 typedef struct ScrArea_Runtime {
        struct bToolRef *tool;
        char          is_tool_set;
index 588d90fae8d22bc6a219a3f47c977860e6a15b4b..3bc5118c99651f59d8763f01bc89619c8b9caa29 100644 (file)
@@ -67,9 +67,9 @@ struct MovieClipScopes;
 struct Mask;
 struct BLI_mempool;
 
-/* TODO 2.8: We don't write the topbar to files currently. Uncomment this
+/* TODO 2.8: We don't write the global areas to files currently. Uncomment
  * define to enable writing (should become the default in a bit). */
-//#define WITH_TOPBAR_WRITING
+//#define WITH_GLOBAL_AREA_WRITING
 
 
 /* SpaceLink (Base) ==================================== */
@@ -1327,7 +1327,7 @@ typedef enum eSpaceClip_GPencil_Source {
 /* Top Bar ======================================= */
 
 /* These two lines with # tell makesdna this struct can be excluded.
- * Should be: #ifndef WITH_TOPBAR_WRITING */
+ * Should be: #ifndef WITH_GLOBAL_AREA_WRITING */
 #
 #
 typedef struct SpaceTopBar {
@@ -1338,6 +1338,20 @@ typedef struct SpaceTopBar {
        int pad;
 } SpaceTopBar;
 
+/* Status Bar ======================================= */
+
+/* These two lines with # tell makesdna this struct can be excluded.
+ * Should be: #ifndef WITH_GLOBAL_AREA_WRITING */
+#
+#
+typedef struct SpaceStatusBar {
+       SpaceLink *next, *prev;
+       ListBase regionbase;        /* storage of regions for inactive spaces */
+       int spacetype;
+
+       int pad;
+} SpaceStatusBar;
+
 
 /* **************** SPACE DEFINES ********************* */
 
@@ -1369,8 +1383,9 @@ typedef enum eSpace_Type {
        SPACE_USERPREF = 19,
        SPACE_CLIP     = 20,
        SPACE_TOPBAR   = 21,
+       SPACE_STATUSBAR = 22,
 
-       SPACE_TYPE_LAST = SPACE_TOPBAR
+       SPACE_TYPE_LAST = SPACE_STATUSBAR
 } eSpace_Type;
 
 /* use for function args */
index 83d8e730e3ea6885dab9eb95b2c83af2e635ad99..b8c7eff624195d6f1a595f755af0cceb6570bdf9 100644 (file)
@@ -145,7 +145,7 @@ static const EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C), PointerR
 
        /* +1 to skip SPACE_EMPTY */
        for (const EnumPropertyItem *item_from = rna_enum_space_type_items + 1; item_from->identifier; item_from++) {
-               if (ELEM(item_from->value, SPACE_TOPBAR)) {
+               if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
                        continue;
                }
                RNA_enum_item_add(&item, &totitem, item_from);
@@ -166,7 +166,7 @@ static int rna_Area_type_get(PointerRNA *ptr)
 
 static void rna_Area_type_set(PointerRNA *ptr, int value)
 {
-       if (ELEM(value, SPACE_TOPBAR)) {
+       if (ELEM(value, SPACE_TOPBAR, SPACE_STATUSBAR)) {
                /* Special case: An area can not be set to show the top-bar editor (or
                 * other global areas). However it should still be possible to identify
                 * its type from Python. */
index fa4eb2f4962a30d3528514b89f76d1659711ae88..e555c2ae52a2cc923a7ed9ad39484fd7764eb371 100644 (file)
@@ -90,8 +90,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = {
                        "advanced editing and script development"},
        {SPACE_INFO, "INFO", ICON_INFO, "Info", "Main menu bar and list of error messages "
                     "(drag down to expand and display)"},
-       /* Special case: Top-bar isn't supposed to be a regular editor for the user. */
-       {SPACE_TOPBAR, "TOPBAR", ICON_NONE, "Top Bar", "Global bar at the top of the screen for global per-window settings"},
+       /* Special case: Top-bar and Status-bar aren't supposed to be a regular editor for the user. */
+       {SPACE_TOPBAR, "TOPBAR", ICON_NONE, "Top Bar", "Global bar at the top of the screen for "
+                      "global per-window settings"},
+       {SPACE_STATUSBAR, "STATUSBAR", ICON_NONE, "Status Bar", "Global bar at the bottom of the "
+                         "screen for general status information"},
 
        /* Data */
        {0, "", ICON_NONE, "Data", ""},
index 9e47179c6151e61e8f0f130c705b40ce746159b2..d941ef02ee0f07516ed4e7c6c807abaf3c3619e8 100644 (file)
@@ -102,8 +102,8 @@ void                WM_check                        (struct bContext *C);
 
 int WM_window_pixels_x(const struct wmWindow *win);
 int WM_window_pixels_y(const struct wmWindow *win);
-int WM_window_screen_pixels_x(const struct wmWindow *win);
-int WM_window_screen_pixels_y(const struct wmWindow *win);
+void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
+void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
 bool WM_window_is_fullscreen(struct wmWindow *win);
 
 void WM_windows_scene_data_sync(const ListBase *win_lb, struct Scene *scene) ATTR_NONNULL();
index ef1e4d24e7f7b0199f51a2198611f72a2c81af80..0c3d2544bb453fe8ee77708bfe6e5ec781afbed3 100644 (file)
@@ -2135,23 +2135,44 @@ int WM_window_pixels_y(const wmWindow *win)
 }
 
 /**
- * Get the total pixels that are usable by the screen-layouts, excluding global areas.
+ * Get boundaries usable by all window contents, including global areas.
  */
-int WM_window_screen_pixels_x(const wmWindow *win)
+void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
 {
-       return WM_window_pixels_x(win);
+       BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
 }
-int WM_window_screen_pixels_y(const wmWindow *win)
+/**
+ * Get boundaries usable by screen-layouts, excluding global areas.
+ * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
+ */
+void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
 {
-       short screen_size_y = WM_window_pixels_y(win);
+       rcti rect;
 
-       for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
-               if ((sa->global->flag & GLOBAL_AREA_IS_HIDDEN) == 0) {
-                       screen_size_y -= ED_area_global_size_y(sa);
+       BLI_rcti_init(&rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
+
+       /* Substract global areas from screen rectangle. */
+       for (ScrArea *global_area = win->global_areas.areabase.first; global_area; global_area = global_area->next) {
+               if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
+                       continue;
+               }
+
+               switch (global_area->global->align) {
+                       case GLOBAL_AREA_ALIGN_TOP:
+                               rect.ymax -= ED_area_global_size_y(global_area);
+                               break;
+                       case GLOBAL_AREA_ALIGN_BOTTOM:
+                               rect.ymin += ED_area_global_size_y(global_area);
+                               break;
+                       default:
+                               BLI_assert(0);
+                               break;
                }
        }
 
-       return screen_size_y;
+       BLI_assert(rect.xmin < rect.xmax);
+       BLI_assert(rect.ymin < rect.ymax);
+       *r_rect = rect;
 }
 
 bool WM_window_is_fullscreen(wmWindow *win)