Interface: New region type 'Footer', used by text editor
authorGeorge Vogiatzis <Gvgeo>
Fri, 5 Apr 2019 11:48:26 +0000 (13:48 +0200)
committerJacques Lucke <mail@jlucke.com>
Fri, 5 Apr 2019 11:48:26 +0000 (13:48 +0200)
* It can be hidden by dragging it up/down.
* It can be at the top or bottom, independent of the header.
* It uses the color theme from the header.
* It does not change its color, when the area becomes active.

Currently, it is used in the text editor to display the file path.

Differential Revision: https://developer.blender.org/D4601

18 files changed:
release/scripts/modules/bl_keymap_utils/keymap_hierarchy.py
release/scripts/presets/keyconfig/keymap_data/blender_default.py
release/scripts/startup/bl_ui/space_text.py
source/blender/blenkernel/intern/screen.c
source/blender/blenloader/intern/versioning_280.c
source/blender/editors/include/ED_screen.h
source/blender/editors/interface/interface_context_menu.c
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_region_menu_popup.c
source/blender/editors/interface/interface_region_popover.c
source/blender/editors/interface/resources.c
source/blender/editors/screen/area.c
source/blender/editors/screen/screen_edit.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/space_text/space_text.c
source/blender/makesdna/DNA_screen_types.h
source/blender/makesrna/intern/rna_screen.c
source/blender/windowmanager/intern/wm_event_system.c

index e64c78f..4fae134 100644 (file)
@@ -55,6 +55,7 @@ _km_hierarchy = [
     ('Screen', 'EMPTY', 'WINDOW', [     # full screen, undo, screenshot
         ('Screen Editing', 'EMPTY', 'WINDOW', []),    # re-sizing, action corners
         ('Header', 'EMPTY', 'WINDOW', []),            # header stuff (per region)
+        ('Footer', 'EMPTY', 'WINDOW', []),            # footer stuff (per region)
     ]),
 
     ('View2D', 'EMPTY', 'WINDOW', []),    # view 2d navigation (per region)
index 84e97d5..9d4fcf7 100644 (file)
@@ -535,6 +535,21 @@ def km_header(_params):
     return keymap
 
 
+def km_footer(_params):
+    items = []
+    keymap = (
+        "Footer",
+        {"space_type": 'EMPTY', "region_type": 'WINDOW'},
+        {"items": items},
+    )
+
+    items.extend([
+        ("screen.footer_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None),
+    ])
+
+    return keymap
+
+
 def km_view2d(_params):
     items = []
     keymap = (
@@ -6032,6 +6047,7 @@ def generate_keymaps(params=None):
         km_screen(params),
         km_screen_editing(params),
         km_header(params),
+        km_footer(params),
         km_view2d(params),
         km_view2d_buttons_list(params),
         km_user_interface(params),
index 6726a5d..b62e2d7 100644 (file)
@@ -56,6 +56,29 @@ class TEXT_HT_header(Header):
         if text:
             is_osl = text.name.endswith((".osl", ".osl"))
 
+            row = layout.row()
+            if is_osl:
+                row = layout.row()
+                row.operator("node.shader_script_update")
+            else:
+                row = layout.row()
+                row.active = text.name.endswith(".py")
+                row.prop(text, "use_module")
+
+                row = layout.row()
+                row.operator("text.run_script")
+
+
+class TEXT_HT_footer(Header):
+    bl_space_type = 'TEXT_EDITOR'
+    bl_region_type = 'FOOTER'
+
+    def draw(self, context):
+        layout = self.layout
+
+        st = context.space_data
+        text = st.text
+        if text:
             row = layout.row()
             if text.filepath:
                 if text.is_dirty:
@@ -74,16 +97,6 @@ class TEXT_HT_header(Header):
                     if text.library
                     else "Text: Internal"
                 )
-            if is_osl:
-                row = layout.row()
-                row.operator("node.shader_script_update")
-            else:
-                row = layout.row()
-                row.active = text.name.endswith(".py")
-                row.prop(text, "use_module")
-
-                row = layout.row()
-                row.operator("text.run_script")
 
 
 class TEXT_MT_editor_menus(Menu):
@@ -353,6 +366,7 @@ class TEXT_MT_toolbox(Menu):
 
 classes = (
     TEXT_HT_header,
+    TEXT_HT_footer,
     TEXT_MT_edit,
     TEXT_MT_editor_menus,
     TEXT_PT_properties,
index 7a2b93e..7b4b116 100644 (file)
@@ -860,6 +860,13 @@ void BKE_screen_header_alignment_reset(bScreen *screen)
                                }
                                ar->alignment = alignment;
                        }
+                       if (ar->regiontype == RGN_TYPE_FOOTER) {
+                               if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
+                                       ar->alignment = RGN_ALIGN_BOTTOM;
+                                       continue;
+                               }
+                               ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
+                       }
                }
        }
        screen->do_refresh = true;
index a1087ca..5c0ff1a 100644 (file)
@@ -2969,5 +2969,29 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
 
        {
                /* Versioning code until next subversion bump goes here. */
+
+               for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+                       for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+                               for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+                                       if (sl->spacetype == SPACE_TEXT) {
+                                               ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+                                               ARegion *ar = MEM_callocN(sizeof(ARegion), "footer for text");
+                                               ARegion *ar_header = NULL;
+
+                                               for (ar_header = regionbase->first; ar_header; ar_header = ar_header->next) {
+                                                       if (ar_header->regiontype == RGN_TYPE_HEADER) {
+                                                               break;
+                                                       }
+                                               }
+                                               BLI_assert(ar_header);
+
+                                               BLI_insertlinkafter(regionbase, ar_header, ar);
+
+                                               ar->regiontype = RGN_TYPE_FOOTER;
+                                               ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
+                                       }
+                               }
+                       }
+               }
        }
 }
index f44f951..10a1eab 100644 (file)
@@ -147,6 +147,9 @@ void    ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2);
 int     ED_area_headersize(void);
 int     ED_area_header_alignment_or_fallback(const ScrArea *area, int fallback);
 int     ED_area_header_alignment(const ScrArea *area);
+int     ED_area_footersize(void);
+int     ED_area_footer_alignment_or_fallback(const ScrArea *area, int fallback);
+int     ED_area_footer_alignment(const ScrArea *area);
 int     ED_area_global_size_y(const ScrArea *area);
 int     ED_area_global_min_size_y(const ScrArea *area);
 int     ED_area_global_max_size_y(const ScrArea *area);
@@ -192,6 +195,7 @@ void    ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
 void    ED_screen_full_restore(struct bContext *C, ScrArea *sa);
 struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *sa, const short state);
 void    ED_screens_header_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
+void    ED_screens_footer_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
 void    ED_screens_navigation_bar_tools_menu_create(struct bContext *C, struct uiLayout *layout, void *arg);
 bool    ED_screen_stereo3d_required(const struct bScreen *screen, const struct Scene *scene);
 Scene   *ED_screen_scene_find(const struct bScreen *screen, const struct wmWindowManager *wm);
@@ -365,6 +369,7 @@ enum {
        ED_KEYMAP_FRAMES    = (1 << 7),
        ED_KEYMAP_HEADER    = (1 << 8),
        ED_KEYMAP_GPENCIL   = (1 << 9),
+       ED_KEYMAP_FOOTER    = (1 << 10),
 };
 
 /* SCREEN_OT_space_context_cycle direction */
index b5eb630..4ca92fb 100644 (file)
@@ -847,6 +847,9 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
                else if (ar->regiontype == RGN_TYPE_NAV_BAR) {
                        uiItemMenuF(layout, IFACE_("Navigation Bar"), ICON_NONE, ED_screens_navigation_bar_tools_menu_create, NULL);
                }
+               else if (ar->regiontype == RGN_TYPE_FOOTER) {
+                       uiItemMenuF(layout, IFACE_("Footer"), ICON_NONE, ED_screens_footer_tools_menu_create, NULL);
+               }
        }
 
        MenuType *mt = WM_menutype_find("WM_MT_button_context", true);
index 208c1a9..07be225 100644 (file)
@@ -1784,7 +1784,7 @@ static bool ui_but_drag_init(
 
                        /* Initialize alignment for single row/column regions,
                         * otherwise we use the relative position of the first other button dragged over. */
-                       if (ELEM(data->region->regiontype, RGN_TYPE_NAV_BAR, RGN_TYPE_HEADER)) {
+                       if (ELEM(data->region->regiontype, RGN_TYPE_NAV_BAR, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                int lock_axis = -1;
                                if (ELEM(data->region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
                                        lock_axis = 0;
index a20c4fe..0fe847c 100644 (file)
@@ -278,11 +278,19 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
                /* for a header menu we set the direction automatic */
                if (!pup->slideout && flip) {
                        ScrArea *sa = CTX_wm_area(C);
-                       if (sa && ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
-                               ARegion *ar = CTX_wm_region(C);
-                               if (ar && ar->regiontype == RGN_TYPE_HEADER) {
-                                       UI_block_direction_set(block, UI_DIR_UP);
-                                       UI_block_order_flip(block);
+                       ARegion *ar = CTX_wm_region(C);
+                       if (sa && ar) {
+                               if (ar->regiontype == RGN_TYPE_HEADER) {
+                                       if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+                                               UI_block_direction_set(block, UI_DIR_UP);
+                                               UI_block_order_flip(block);
+                                       }
+                               }
+                               if (ar->regiontype == RGN_TYPE_FOOTER) {
+                                       if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) {
+                                               UI_block_direction_set(block, UI_DIR_UP);
+                                               UI_block_order_flip(block);
+                                       }
                                }
                        }
                }
index 0b1d3f1..7ca6db2 100644 (file)
@@ -180,10 +180,17 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
                                 * see the values of the buttons below changing. */
                                UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
                        }
-                       else if (sa && ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
-                               /* Prefer popover from header to be positioned into the editor. */
-                               if (ar && ar->regiontype == RGN_TYPE_HEADER) {
-                                       UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
+                       /* Prefer popover from header to be positioned into the editor. */
+                       else if (sa && ar) {
+                               if (ar->regiontype == RGN_TYPE_HEADER){
+                                       if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
+                                               UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
+                                       }
+                               }
+                               if (ar->regiontype == RGN_TYPE_FOOTER) {
+                                       if (ED_area_footer_alignment(sa) == RGN_ALIGN_BOTTOM) {
+                                               UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
+                                       }
                                }
                        }
                }
index 72739b9..8d90837 100644 (file)
@@ -173,7 +173,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
                                        else if (theme_regionid == RGN_TYPE_CHANNELS) {
                                                cp = ts->list;
                                        }
-                                       else if (theme_regionid == RGN_TYPE_HEADER) {
+                                       else if (ELEM(theme_regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                                cp = ts->header;
                                        }
                                        else if (theme_regionid == RGN_TYPE_NAV_BAR) {
@@ -207,7 +207,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
                                        else if (theme_regionid == RGN_TYPE_CHANNELS) {
                                                cp = ts->list_text;
                                        }
-                                       else if (theme_regionid == RGN_TYPE_HEADER) {
+                                       else if (ELEM(theme_regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                                cp = ts->header_text;
                                        }
                                        else {
@@ -221,7 +221,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
                                        else if (theme_regionid == RGN_TYPE_CHANNELS) {
                                                cp = ts->list_text_hi;
                                        }
-                                       else if (theme_regionid == RGN_TYPE_HEADER) {
+                                       else if (ELEM(theme_regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                                cp = ts->header_text_hi;
                                        }
                                        else {
@@ -235,7 +235,7 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid)
                                        else if (theme_regionid == RGN_TYPE_CHANNELS) {
                                                cp = ts->list_title;
                                        }
-                                       else if (theme_regionid == RGN_TYPE_HEADER) {
+                                       else if (ELEM(theme_regionid, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                                cp = ts->header_title;
                                        }
                                        else {
index 886f278..0150127 100644 (file)
@@ -1111,15 +1111,9 @@ bool ED_region_is_overlap(int spacetype, int regiontype)
                        }
                }
                else if (ELEM(spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
-                       if (ELEM(regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS)) {
+                       if (ELEM(regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                return true;
                        }
-
-                       if (ELEM(spacetype, SPACE_VIEW3D, SPACE_IMAGE)) {
-                               if (regiontype == RGN_TYPE_HEADER) {
-                                       return true;
-                               }
-                       }
                }
        }
 
@@ -1167,6 +1161,9 @@ static void region_rect_recursive(ScrArea *sa, ARegion *ar, rcti *remainder, rct
        else if (ar->regiontype == RGN_TYPE_HEADER) {
                prefsizey = ED_area_headersize();
        }
+       else if (ar->regiontype == RGN_TYPE_FOOTER) {
+               prefsizey = ED_area_footersize();
+       }
        else if (ED_area_is_global(sa)) {
                prefsizey = ED_region_global_size_y();
        }
@@ -1520,6 +1517,11 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ARegion *ar, L
                wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Header", 0, 0);
                WM_event_add_keymap_handler(handlers, keymap);
        }
+       if (flag & ED_KEYMAP_FOOTER) {
+               /* standard keymap for footer regions */
+               wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "Footer", 0, 0);
+               WM_event_add_keymap_handler(handlers, keymap);
+       }
 
        /* Keep last because of LMB/RMB handling, see: T57527. */
        if (flag & ED_KEYMAP_GPENCIL) {
@@ -1910,10 +1912,25 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
 
                /* Sync header alignment. */
                if (sync_header_alignment) {
-                       for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
-                               if (ar->regiontype == RGN_TYPE_HEADER) {
-                                       ar->alignment = header_alignment;
-                                       break;
+                       /* Spaces with footer. */
+                       if (st->spaceid == SPACE_TEXT){
+                               for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+                                       if (ar->regiontype == RGN_TYPE_HEADER) {
+                                               ar->alignment = header_alignment;
+                                       }
+                                       if (ar->regiontype == RGN_TYPE_FOOTER) {
+                                               int footer_alignment = (header_alignment == RGN_ALIGN_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
+                                               ar->alignment = footer_alignment;
+                                               break;
+                                       }
+                               }
+                       }
+                       else {
+                               for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+                                       if (ar->regiontype == RGN_TYPE_HEADER) {
+                                               ar->alignment = header_alignment;
+                                               break;
+                                       }
                                }
                        }
                }
@@ -2538,6 +2555,27 @@ int ED_area_header_alignment(const ScrArea *area)
                area, (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP);
 }
 
+int ED_area_footersize(void)
+{
+       return ED_area_headersize();
+}
+
+int ED_area_footer_alignment_or_fallback(const ScrArea *area, int fallback)
+{
+       for (ARegion *ar = area->regionbase.first; ar; ar = ar->next) {
+               if (ar->regiontype == RGN_TYPE_FOOTER) {
+                       return ar->alignment;
+               }
+       }
+       return fallback;
+}
+
+int ED_area_footer_alignment(const ScrArea *area)
+{
+       return ED_area_footer_alignment_or_fallback(
+                       area, (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM);
+}
+
 /**
  * \return the final height of a global \a area, accounting for DPI.
  */
index cd5b557..41ce545 100644 (file)
@@ -421,7 +421,11 @@ static void screen_refresh_headersizes(void)
        SpaceType *st;
 
        for (st = lb->first; st; st = st->next) {
-               ARegionType *art = BKE_regiontype_from_id(st, RGN_TYPE_HEADER);
+               ARegionType *art;
+               art = BKE_regiontype_from_id(st, RGN_TYPE_HEADER);
+               if (art) art->prefsizey = ED_area_headersize();
+
+               art = BKE_regiontype_from_id(st, RGN_TYPE_FOOTER);
                if (art) art->prefsizey = ED_area_headersize();
        }
 }
@@ -1259,7 +1263,8 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
                        for (ar = newa->regionbase.first; ar; ar = ar->next) {
                                ar->flagfullscreen = ar->flag;
 
-                               if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_HEADER, RGN_TYPE_TOOLS, RGN_TYPE_NAV_BAR, RGN_TYPE_EXECUTE)) {
+                               if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_HEADER, RGN_TYPE_FOOTER,
+                                                        RGN_TYPE_TOOLS, RGN_TYPE_NAV_BAR, RGN_TYPE_EXECUTE)) {
                                        ar->flag |= RGN_FLAG_HIDDEN;
                                }
                        }
index ed96621..09ca047 100644 (file)
@@ -2317,12 +2317,13 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
                                dist -= ar->winx;
                        }
                        else if (scalear->alignment == RGN_ALIGN_TOP &&
-                                (ar->alignment == RGN_ALIGN_BOTTOM || ar->regiontype == RGN_TYPE_HEADER))
+                                (ar->alignment == RGN_ALIGN_BOTTOM || ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)))
                        {
                                dist -= ar->winy;
                        }
                        else if (scalear->alignment == RGN_ALIGN_BOTTOM &&
-                                (ar->alignment == RGN_ALIGN_TOP || ar->regiontype == RGN_TYPE_HEADER)) {
+                                (ar->alignment == RGN_ALIGN_TOP || ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)))
+                       {
                                dist -= ar->winy;
                        }
                }
@@ -2469,8 +2470,8 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
                                }
                                CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
 
-                               /* note, 'UI_UNIT_Y/4' means you need to drag the header almost
-                                * all the way down for it to become hidden, this is done
+                               /* note, 'UI_UNIT_Y/4' means you need to drag the footer and execute region
+                                * almost all the way down for it to become hidden, this is done
                                 * otherwise its too easy to do this by accident */
                                if (rmd->ar->sizey < UI_UNIT_Y / 4) {
                                        rmd->ar->sizey = rmd->origval;
@@ -3849,6 +3850,103 @@ static void SCREEN_OT_header_context_menu(wmOperatorType *ot)
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Footer Toggle Operator
+ * \{ */
+
+static int footer_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       ARegion *ar = screen_find_region_type(C, RGN_TYPE_FOOTER);
+
+       if (ar == NULL) {
+               return OPERATOR_CANCELLED;
+       }
+
+       ar->flag ^= RGN_FLAG_HIDDEN;
+
+       ED_area_tag_redraw(CTX_wm_area(C));
+
+       WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_footer(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Toggle Footer";
+       ot->description = "Toggle footer display";
+       ot->idname = "SCREEN_OT_footer";
+
+       /* api callbacks */
+       ot->exec = footer_exec;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Footer Tools Operator
+ * \{ */
+
+static bool footer_context_menu_poll(bContext *C)
+{
+       ScrArea *sa = CTX_wm_area(C);
+       return sa;
+}
+
+void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *UNUSED(arg))
+{
+       ScrArea *sa = CTX_wm_area(C);
+       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 Footer"), ICON_NONE, "SCREEN_OT_footer");
+
+       /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
+       uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_DEFAULT);
+
+       uiItemO(layout, but_flip_str, ICON_NONE, "SCREEN_OT_region_flip");
+
+
+       /* 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)) {
+               uiItemS(layout);
+
+               const char *but_str = sa->full ? IFACE_("Tile Area") : IFACE_("Maximize Area");
+               uiItemO(layout, but_str, ICON_NONE, "SCREEN_OT_screen_full_area");
+       }
+}
+
+static int footer_context_menu_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+{
+       uiPopupMenu *pup;
+       uiLayout *layout;
+
+       pup = UI_popup_menu_begin(C, IFACE_("Footer"), ICON_NONE);
+       layout = UI_popup_menu_layout(pup);
+
+       ED_screens_footer_tools_menu_create(C, layout, NULL);
+
+       UI_popup_menu_end(C, pup);
+
+       return OPERATOR_INTERFACE;
+}
+
+static void SCREEN_OT_footer_context_menu(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Footer Context Menu";
+       ot->description = "Display footer region context menu";
+       ot->idname = "SCREEN_OT_footer_context_menu";
+
+       /* api callbacks */
+       ot->poll = footer_context_menu_poll;
+       ot->invoke = footer_context_menu_invoke;
+}
+
+/** \} */
+
 /* -------------------------------------------------------------------- */
 /** \name Navigation Bar Tools Menu
  * \{ */
@@ -4968,6 +5066,8 @@ void ED_operatortypes_screen(void)
        WM_operatortype_append(SCREEN_OT_header);
        WM_operatortype_append(SCREEN_OT_header_toggle_menus);
        WM_operatortype_append(SCREEN_OT_header_context_menu);
+       WM_operatortype_append(SCREEN_OT_footer);
+       WM_operatortype_append(SCREEN_OT_footer_context_menu);
        WM_operatortype_append(SCREEN_OT_screen_set);
        WM_operatortype_append(SCREEN_OT_screen_full_area);
        WM_operatortype_append(SCREEN_OT_back_to_previous);
index cd5b3fa..55165e4 100644 (file)
@@ -74,6 +74,12 @@ static SpaceLink *text_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen
        ar->regiontype = RGN_TYPE_HEADER;
        ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
 
+       /* footer */
+       ar = MEM_callocN(sizeof(ARegion), "footer for text");
+       BLI_addtail(&stext->regionbase, ar);
+       ar->regiontype = RGN_TYPE_FOOTER;
+       ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM;
+
        /* properties region */
        ar = MEM_callocN(sizeof(ARegion), "properties region for text");
 
@@ -469,7 +475,15 @@ void ED_spacetype_text(void)
 
        art->init = text_header_region_init;
        art->draw = text_header_region_draw;
+       BLI_addhead(&st->regiontypes, art);
 
+       /* regions: footer */
+       art = MEM_callocN(sizeof(ARegionType), "spacetype text region");
+       art->regionid = RGN_TYPE_FOOTER;
+       art->prefsizey = HEADERY;
+       art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FOOTER;
+       art->init = text_header_region_init;
+       art->draw = text_header_region_draw;
        BLI_addhead(&st->regiontypes, art);
 
        BKE_spacetype_register(st);
index fb111fa..a04d16b 100644 (file)
@@ -590,8 +590,9 @@ enum {
        RGN_TYPE_HUD = 8,
        /* Region to navigate the main region from (RGN_TYPE_WINDOW). */
        RGN_TYPE_NAV_BAR = 9,
-       /* A place for buttons to trigger execution of somthing that was set up in other regions. */
+       /* A place for buttons to trigger execution of something that was set up in other regions. */
        RGN_TYPE_EXECUTE = 10,
+       RGN_TYPE_FOOTER = 11,
 };
 /* use for function args */
 #define RGN_TYPE_ANY -1
index c42bfd5..a6f321e 100644 (file)
@@ -43,6 +43,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
        {RGN_TYPE_HUD, "HUD", 0, "Floating Region", ""},
        {RGN_TYPE_NAV_BAR, "NAVIGATION_BAR", 0, "Navigation Bar", ""},
        {RGN_TYPE_EXECUTE, "EXECUTE", 0, "Execute Buttons", ""},
+       {RGN_TYPE_FOOTER, "FOOTER", 0, "Footer", ""},
        {0, NULL, 0, NULL, NULL},
 };
 
index 70c2470..940e7fa 100644 (file)
@@ -1401,7 +1401,7 @@ static int wm_operator_invoke(
                                /* exception, cont. grab in header is annoying */
                                if (wrap) {
                                        ARegion *ar = CTX_wm_region(C);
-                                       if (ar && ar->regiontype == RGN_TYPE_HEADER) {
+                                       if (ar && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
                                                wrap = false;
                                        }
                                }
@@ -4699,7 +4699,7 @@ void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
        if (ELEM(sa->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
                return;
        }
-       if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TEMPORARY, RGN_TYPE_HUD)) {
+       if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER, RGN_TYPE_TEMPORARY, RGN_TYPE_HUD)) {
                return;
        }
        /* Fallback to window. */