UI: Vertical Properties Editor Tabs
authorJulian Eisel <eiseljulian@gmail.com>
Mon, 29 Oct 2018 20:34:14 +0000 (21:34 +0100)
committerJulian Eisel <eiseljulian@gmail.com>
Mon, 29 Oct 2018 20:44:01 +0000 (21:44 +0100)
Moves the Properties editor context switching to a vertical tabs region.

Design Task: T54951
Differential Revison: D3840

The tabs are regular widgets, unlike the 'old' toolshelf tabs. This means they
give mouse hover feedback, have tooltips, support the right-click menu, etc.
Also, when vertical screen space gets tight, the tabs can be scrolled, they
don't shrink like the toolshelf ones.
The tab region is slightly larger than the header. The tabs are scaled up
accordingly. This makes them nicely readable.

The header is quite empty now. As shown in T54951, we wanted to have a search
button there. This should be added next.

Implementation Notes:

* Added a new region type, RGN_TYPE_NAVIGATION.
* Having the tabs in a separate region allows scrolling of the tab-bar, unlike
  the toolshelf tabs. We might want to remove the scrollbars though.
* Added a new region flag RGN_FLAG_PREFSIZE_OR_HIDDEN, to ensure the tab region
  is either hidden or has a fixed size.
* Added some additional flags to support fine-tuning the layout in panel and
  layout code.
* Bumps subversion.

16 files changed:
release/scripts/startup/bl_ui/space_properties.py
source/blender/blenkernel/BKE_blender_version.h
source/blender/blenloader/intern/versioning_280.c
source/blender/blenloader/intern/versioning_userdef.c
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_layout.c
source/blender/editors/interface/interface_panel.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_buttons/space_buttons.c
source/blender/makesdna/DNA_screen_types.h
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_userdef.c

index 2d1725b208774af1e863fe2968c05ee119c30e61..b60e1e7d6fb316b42ffb1a6aae6459db35582113 100644 (file)
@@ -18,7 +18,7 @@
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Header
+from bpy.types import Header, Panel
 
 
 class PROPERTIES_HT_header(Header):
@@ -27,16 +27,29 @@ class PROPERTIES_HT_header(Header):
     def draw(self, context):
         layout = self.layout
 
-        view = context.space_data
-
         row = layout.row()
         row.template_header()
 
-        row.prop(view, "context", expand=True, icon_only=True)
+
+class PROPERTIES_PT_navigation_bar(Panel):
+    bl_space_type = 'PROPERTIES'
+    bl_region_type = 'NAVIGATION_BAR'
+    bl_label = "Navigation Bar"
+    bl_options = {'HIDE_HEADER'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        view = context.space_data
+
+        layout.scale_x = 1.4
+        layout.scale_y = 1.4
+        layout.prop_tabs_enum(view, "context", icon_only=True)
 
 
 classes = (
     PROPERTIES_HT_header,
+    PROPERTIES_PT_navigation_bar,
 )
 
 if __name__ == "__main__":  # only for live edit.
index 6435fe461cc9139efaca8af13090a8940a3b518a..b95e2e504d0f0b1de9745692cf141cb870eeb4ec 100644 (file)
@@ -28,7 +28,7 @@
  * and keep comment above the defines.
  * Use STRINGIFY() rather than defining with quotes */
 #define BLENDER_VERSION         280
-#define BLENDER_SUBVERSION      28
+#define BLENDER_SUBVERSION      29
 /* Several breakages with 280, e.g. collections vs layers */
 #define BLENDER_MINVERSION      280
 #define BLENDER_MINSUBVERSION   0
index 52c83d83454c451f21e0bcb9520fc1e7a32dc799..25c243fa5899e7fb0da0b5f34f7e73fc82884647 100644 (file)
@@ -2179,4 +2179,30 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
                        }
                }
        }
+
+       if (!MAIN_VERSION_ATLEAST(bmain, 280, 29)) {
+               for (bScreen *screen = bmain->screen.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_BUTS) {
+                                               ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+                                               ARegion *ar = MEM_callocN(sizeof(ARegion), "navigation bar for properties");
+                                               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_NAV_BAR;
+                                               ar->alignment = RGN_ALIGN_LEFT;
+                                       }
+                               }
+                       }
+               }
+       }
 }
index b622bc016f5869bc5ea1d99e8a75e2371c35b96d..e3748d9a74b21eb3b4fd4a7340a1883b1ed583d6 100644 (file)
@@ -81,8 +81,12 @@ static void do_versions_theme(UserDef *userdef, bTheme *btheme)
        if (!USER_VERSION_ATLEAST(280, 28)) {
                copy_v4_v4_char(btheme->tact.ds_ipoline, U_theme_default.tact.ds_ipoline);
        }
-#undef USER_VERSION_ATLEAST
 
+       if (!USER_VERSION_ATLEAST(280, 29)) {
+               copy_v4_v4_char(btheme->tbuts.navigation_bar, U_theme_default.ttopbar.header);
+       }
+
+#undef USER_VERSION_ATLEAST
 }
 
 /* patching UserDef struct and Themes */
index efdc9ae011891965f26066b0d37ab113c36b90cf..cbca7c8c9210a07aa5906d1fcfe6087a22f90fb8 100644 (file)
@@ -915,6 +915,7 @@ void UI_exit(void);
 #define UI_LAYOUT_MENU          2
 #define UI_LAYOUT_TOOLBAR       3
 #define UI_LAYOUT_PIEMENU       4
+#define UI_LAYOUT_VERT_BAR      5
 
 #define UI_UNIT_X               ((void)0, U.widget_unit)
 #define UI_UNIT_Y               ((void)0, U.widget_unit)
index a826c55afb547dd1e9d84d347333469acd425fa1..e2b1818c958045730154721261689614e093a0a0 100644 (file)
@@ -4260,7 +4260,7 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s
        root->opcontext = WM_OP_INVOKE_REGION_WIN;
 
        layout = MEM_callocN(sizeof(uiLayout), "uiLayout");
-       layout->item.type = ITEM_LAYOUT_ROOT;
+       layout->item.type = (type == UI_LAYOUT_VERT_BAR) ? ITEM_LAYOUT_COLUMN : ITEM_LAYOUT_ROOT;
 
        /* Only used when 'UI_ITEM_PROP_SEP' is set. */
        layout->item.flag = UI_ITEM_PROP_DECORATE;
index 1897df41fd0778227a09e22259d4e9d9e66f293d..efa3c24afd062590f3c64796fddcc3593dad468f 100644 (file)
@@ -134,7 +134,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar)
                return BUT_VERTICAL;
        else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
                return BUT_VERTICAL;
-       else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS, RGN_TYPE_HUD))
+       else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS, RGN_TYPE_HUD, RGN_TYPE_NAV_BAR))
                return BUT_VERTICAL;
 
        return 0;
index 0ac534e5fcfb380a0af486a86fee4da2e251912b..09b8933206e3723b20e868d402c205d5bf57267f 100644 (file)
@@ -181,6 +181,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
                                                cp = ts->list;
                                        else if (theme_regionid == RGN_TYPE_HEADER)
                                                cp = ts->header;
+                                       else if (theme_regionid == RGN_TYPE_NAV_BAR)
+                                               cp = ts->navigation_bar;
                                        else
                                                cp = ts->button;
 
index b914dd5ecae0351065da23ef137fb2cb5ea933c0..79f2bebd0d3ee8e168037953b3b6b72e8ceee459 100644 (file)
@@ -1159,7 +1159,11 @@ static void region_rect_recursive(ScrArea *sa, ARegion *ar, rcti *remainder, rct
        int prefsizex = UI_DPI_FAC * ((ar->sizex > 1) ? ar->sizex + 0.5f : ar->type->prefsizex);
        int prefsizey;
 
-       if (ar->regiontype == RGN_TYPE_HEADER) {
+       if (ar->flag & RGN_FLAG_PREFSIZE_OR_HIDDEN) {
+               prefsizex = UI_DPI_FAC * ar->type->prefsizex;
+               prefsizey = UI_DPI_FAC * ar->type->prefsizey;
+       }
+       else if (ar->regiontype == RGN_TYPE_HEADER) {
                prefsizey = ED_area_headersize();
        }
        else if (ED_area_is_global(sa)) {
@@ -2020,14 +2024,21 @@ static void ed_panel_draw(
                short panelContext;
 
                /* panel context can either be toolbar region or normal panels region */
-               if (ar->regiontype == RGN_TYPE_TOOLS)
+               if (pt->flag & PNL_LAYOUT_VERT_BAR) {
+                       panelContext = UI_LAYOUT_VERT_BAR;
+               }
+               else if (ar->regiontype == RGN_TYPE_TOOLS) {
                        panelContext = UI_LAYOUT_TOOLBAR;
-               else
+               }
+               else {
                        panelContext = UI_LAYOUT_PANEL;
+               }
 
                panel->layout = UI_block_layout(
                        block, UI_LAYOUT_VERTICAL, panelContext,
-                       style->panelspace, 0, w - 2 * style->panelspace, em, 0, style);
+                       (pt->flag & PNL_LAYOUT_VERT_BAR) ? 0 : style->panelspace, 0,
+                       (pt->flag & PNL_LAYOUT_VERT_BAR) ? 0 : w - 2 * style->panelspace,
+                       em, 0, style);
 
                pt->draw(C, panel);
 
index 8f815dd3b44ea4c1c243e3f2fe81bd10844703d2..f0f8cb6d9d843fe457802116f43d790197f7eb71 100644 (file)
@@ -1251,7 +1251,7 @@ 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)) {
+                               if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_HEADER, RGN_TYPE_TOOLS, RGN_TYPE_NAV_BAR)) {
                                        ar->flag |= RGN_FLAG_HIDDEN;
                                }
                        }
index e570340698f1fe041e00cf940a75d9c27f533c68..3d32f10582d89a84906870d5bcec89891813d180 100644 (file)
@@ -3585,6 +3585,7 @@ static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
                ar->alignment = RGN_ALIGN_LEFT;
 
        ED_area_tag_redraw(CTX_wm_area(C));
+       WM_event_add_mousemove(C);
        WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
 
        return OPERATOR_FINISHED;
index 8d2b5f994b3d879367447e139760cd2dae45d4eb..50018b212a64efaaf7c42e494efbf24178d54202 100644 (file)
@@ -75,6 +75,13 @@ static SpaceLink *buttons_new(const ScrArea *UNUSED(area), const Scene *UNUSED(s
        ar->regiontype = RGN_TYPE_HEADER;
        ar->alignment = RGN_ALIGN_TOP;
 
+       /* navigation bar */
+       ar = MEM_callocN(sizeof(ARegion), "navigation bar for buts");
+
+       BLI_addtail(&sbuts->regionbase, ar);
+       ar->regiontype = RGN_TYPE_NAV_BAR;
+       ar->alignment = RGN_ALIGN_LEFT;
+
 #if 0
        /* context region */
        ar = MEM_callocN(sizeof(ARegion), "context region for buts");
@@ -390,6 +397,21 @@ static void buttons_header_region_message_subscribe(
        }
 }
 
+static void buttons_navigation_bar_region_init(wmWindowManager *wm, ARegion *ar)
+{
+       ar->flag |= RGN_FLAG_PREFSIZE_OR_HIDDEN;
+       ED_region_panels_init(wm, ar);
+       ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y;
+}
+
+static void buttons_navigation_bar_region_draw(const bContext *C, ARegion *ar)
+{
+       for (PanelType *pt = ar->type->paneltypes.first; pt; pt = pt->next) {
+               pt->flag |= PNL_LAYOUT_VERT_BAR;
+       }
+       ED_region_panels(C, ar);
+}
+
 /* draw a certain button set only if properties area is currently
  * showing that button set, to reduce unnecessary drawing. */
 static void buttons_area_redraw(ScrArea *sa, short buttons)
@@ -680,5 +702,14 @@ void ED_spacetype_buttons(void)
        art->message_subscribe = buttons_header_region_message_subscribe;
        BLI_addhead(&st->regiontypes, art);
 
+       /* regions: navigation bar */
+       art = MEM_callocN(sizeof(ARegionType), "spacetype nav buttons region");
+       art->regionid = RGN_TYPE_NAV_BAR;
+       art->prefsizex = AREAMINX - 3; /* XXX Works and looks best, should we update AREAMINX accordingly? */
+       art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES;
+       art->init = buttons_navigation_bar_region_init;
+       art->draw = buttons_navigation_bar_region_draw;
+       BLI_addhead(&st->regiontypes, art);
+
        BKE_spacetype_register(st);
 }
index 50bf24e0b557e7f33e479022404c07655763005c..99404fbf0579ab10b8df80198cad3d79de9da004 100644 (file)
@@ -420,6 +420,7 @@ enum {
 /* paneltype flag */
 #define PNL_DEFAULT_CLOSED             1
 #define PNL_NO_HEADER                  2
+#define PNL_LAYOUT_VERT_BAR            4
 
 /* Fallback panel category (only for old scripts which need updating) */
 #define PNL_CATEGORY_FALLBACK "Misc"
@@ -473,6 +474,8 @@ enum {
        RGN_TYPE_TOOL_PROPS = 6,
        RGN_TYPE_PREVIEW = 7,
        RGN_TYPE_HUD = 8,
+       /* Region to navigate the main region from (RGN_TYPE_WINDOW). */
+       RGN_TYPE_NAV_BAR = 9,
 };
 /* use for function args */
 #define RGN_TYPE_ANY -1
@@ -503,6 +506,8 @@ enum {
        RGN_FLAG_DYNAMIC_SIZE       = (1 << 2),
        /* Region data is NULL'd on read, never written. */
        RGN_FLAG_TEMP_REGIONDATA    = (1 << 3),
+       /* The region must either use its prefsizex/y or be hidden. */
+       RGN_FLAG_PREFSIZE_OR_HIDDEN = (1 << 4),
 };
 
 /* region do_draw */
index d03cd1517c043e051f6e1778db32c31917a81c4e..ebe27cd3b381ba1ce029132142af6713a0fdc18e 100644 (file)
@@ -243,6 +243,10 @@ typedef struct ThemeSpace {
        char list_text[4];
        char list_text_hi[4];
 
+       /* navigation bar regions */
+       char navigation_bar[4];                 /* region background */
+       int pad2;
+
        /* float panel */
 /*     char panel[4];                  unused */
 /*     char panel_title[4];    unused */
index 05e5587c9c468ae7ec544f9f21cba3da79056080..5220d0ef4fb34dfebef46eed3d79ac5317bb9911 100644 (file)
@@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
        {RGN_TYPE_TOOLS, "TOOLS", 0, "Tools", ""},
        {RGN_TYPE_TOOL_PROPS, "TOOL_PROPS", 0, "Tool Properties", ""},
        {RGN_TYPE_PREVIEW, "PREVIEW", 0, "Preview", ""},
+       {RGN_TYPE_NAV_BAR, "NAVIGATION_BAR", 0, "Navigation Bar", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
index bbad0ebf26bdc52c7975968119fd15aa9735a87c..eec0bdccded1a51c45f4102532a22ba20531aee7 100644 (file)
@@ -1325,6 +1325,11 @@ static void rna_def_userdef_theme_space_common(StructRNA *srna)
        RNA_def_property_ui_text(prop, "Region Text Highlight", "");
        RNA_def_property_update(prop, 0, "rna_userdef_update");
 
+       prop = RNA_def_property(srna, "navigation_bar", PROP_FLOAT, PROP_COLOR_GAMMA);
+       RNA_def_property_array(prop, 4);
+       RNA_def_property_ui_text(prop, "Navigation Bar Background", "");
+       RNA_def_property_update(prop, 0, "rna_userdef_update");
+
        /* tabs */
        prop = RNA_def_property(srna, "tab_active", PROP_FLOAT, PROP_COLOR_GAMMA);
        RNA_def_property_array(prop, 3);