UI: move top-bar into the spaces header
authorCampbell Barton <ideasman42@gmail.com>
Thu, 18 Apr 2019 19:13:22 +0000 (21:13 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 19 Apr 2019 04:53:38 +0000 (06:53 +0200)
Currently this is only in the 3D viewport however all spaces
that use the tool-system will have this region added.

D4680 by @brecht with own updates.

21 files changed:
release/scripts/startup/bl_ui/space_image.py
release/scripts/startup/bl_ui/space_topbar.py
release/scripts/startup/bl_ui/space_view3d.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/interface_templates.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_image/space_image.c
source/blender/editors/space_topbar/space_topbar.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/makesdna/DNA_screen_types.h
source/blender/makesrna/intern/rna_screen.c
source/blender/makesrna/intern/rna_space.c
source/blender/windowmanager/intern/wm_event_system.c

index 7d3b766..ef36049 100644 (file)
@@ -506,6 +506,128 @@ class IMAGE_MT_uvs_snap_pie(Menu):
         pie.operator("uv.snap_selected", text="Selected to Adjacent Unselected", icon='RESTRICT_SELECT_OFF').target = 'ADJACENT_UNSELECTED'
 
 
+class IMAGE_HT_tool_header(Header):
+    bl_space_type = 'IMAGE_EDITOR'
+    bl_region_type = "TOOL_HEADER"
+
+    def draw(self, context):
+        layout = self.layout
+
+        layout.row(align=True).template_header()
+
+        self.draw_tool_settings(context)
+
+        sima = context.space_data
+        show_uvedit = sima.show_uvedit
+        show_maskedit = sima.show_maskedit
+
+        layout.separator_spacer()
+
+        if show_uvedit or show_maskedit:
+            layout.prop(sima, "pivot_point", icon_only=True)
+
+        if show_uvedit:
+            tool_settings = context.tool_settings
+
+            # Snap.
+            row = layout.row(align=True)
+            row.prop(tool_settings, "use_snap", text="")
+            row.prop(tool_settings, "snap_uv_element", icon_only=True)
+            if tool_settings.snap_uv_element != 'INCREMENT':
+                row.prop(tool_settings, "snap_target", text="")
+
+            # Proportional Editing
+            row = layout.row(align=True)
+            row.prop(tool_settings, "proportional_edit", icon_only=True)
+            # if tool_settings.proportional_edit != 'DISABLED':
+            sub = row.row(align=True)
+            sub.active = tool_settings.proportional_edit != 'DISABLED'
+            sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
+
+        layout.separator_spacer()
+
+        self.draw_mode_settings(context)
+
+    def draw_tool_settings(self, context):
+        layout = self.layout
+
+        # Active Tool
+        # -----------
+        from .space_toolsystem_common import ToolSelectPanelHelper
+        tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
+        tool_mode = context.mode if tool is None else tool.mode
+
+        # Object Mode Options
+        # -------------------
+
+        # Example of how tool_settings can be accessed as pop-overs.
+
+        # TODO(campbell): editing options should be after active tool options
+        # (obviously separated for from the users POV)
+        draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
+        if draw_fn is not None:
+            draw_fn(context, layout, tool)
+
+        if tool_mode == 'PAINT':
+            if (tool is not None) and tool.has_datablock:
+                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common_2d", category="")
+        elif context.uv_sculpt_object is not None:
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".uv_sculpt", category="")
+
+    def draw_mode_settings(self, context):
+        layout = self.layout
+
+        # Active Tool
+        # -----------
+        from .space_toolsystem_common import ToolSelectPanelHelper
+        tool = ToolSelectPanelHelper.tool_active_from_context(context)
+        tool_mode = context.mode if tool is None else tool.mode
+
+        if tool_mode == 'PAINT':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".imagepaint_2d", category="")
+
+
+class _draw_tool_settings_context_mode:
+    @staticmethod
+    def VIEW(context, layout, tool):
+        tool_settings = context.tool_settings
+        if tool_settings.use_uv_sculpt:
+            if context.mode == 'EDIT_MESH':
+                uv_sculpt = tool_settings.uv_sculpt
+                brush = uv_sculpt.brush
+                if brush:
+                    from .properties_paint_common import UnifiedPaintPanel
+
+                    row = layout.row(align=True)
+                    UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
+                    UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
+
+                    row = layout.row(align=True)
+                    UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
+                    UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
+
+    @staticmethod
+    def PAINT(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+
+        paint = context.tool_settings.image_paint
+        layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
+
+        brush = paint.brush
+        if brush is None:
+            return
+
+        from .properties_paint_common import (
+            UnifiedPaintPanel,
+            brush_basic_texpaint_settings,
+        )
+        capabilities = brush.image_paint_capabilities
+        if capabilities.has_color:
+            UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
+        brush_basic_texpaint_settings(layout, context, brush, compact=True)
+
+
 class IMAGE_HT_header(Header):
     bl_space_type = 'IMAGE_EDITOR'
 
@@ -521,8 +643,8 @@ class IMAGE_HT_header(Header):
         show_uvedit = sima.show_uvedit
         show_maskedit = sima.show_maskedit
 
-        row = layout.row(align=True)
-        row.template_header()
+        if not sima.show_region_tool_header:
+            layout.row(align=True).template_header()
 
         if sima.mode != 'UV':
             layout.prop(sima, "ui_mode", text="")
@@ -560,25 +682,6 @@ class IMAGE_HT_header(Header):
             mesh = context.edit_object.data
             layout.prop_search(mesh.uv_layers, "active", mesh, "uv_layers", text="")
 
-        if show_uvedit or show_maskedit:
-            layout.prop(sima, "pivot_point", icon_only=True)
-
-        if show_uvedit:
-            # Snap.
-            row = layout.row(align=True)
-            row.prop(tool_settings, "use_snap", text="")
-            row.prop(tool_settings, "snap_uv_element", icon_only=True)
-            if tool_settings.snap_uv_element != 'INCREMENT':
-                row.prop(tool_settings, "snap_target", text="")
-
-            # Proportional Editing
-            row = layout.row(align=True)
-            row.prop(tool_settings, "proportional_edit", icon_only=True)
-            # if tool_settings.proportional_edit != 'DISABLED':
-            sub = row.row(align=True)
-            sub.active = tool_settings.proportional_edit != 'DISABLED'
-            sub.prop(tool_settings, "proportional_edit_falloff", icon_only=True)
-
         row = layout.row()
         row.popover(
             panel="IMAGE_PT_view_display",
@@ -1494,6 +1597,7 @@ classes = (
     IMAGE_MT_uvs_context_menu,
     IMAGE_MT_pivot_pie,
     IMAGE_MT_uvs_snap_pie,
+    IMAGE_HT_tool_header,
     IMAGE_HT_header,
     MASK_MT_editor_menus,
     IMAGE_PT_mask,
index 7598c69..04908ee 100644 (file)
@@ -80,399 +80,6 @@ class TOPBAR_HT_upper_bar(Header):
             unlink="scene.view_layer_remove")
 
 
-class TOPBAR_HT_lower_bar(Header):
-    bl_space_type = 'TOPBAR'
-    bl_region_type = 'WINDOW'
-
-    def draw(self, context):
-        region = context.region
-
-        if region.alignment == 'RIGHT':
-            self.draw_right(context)
-        else:
-            self.draw_left(context)
-
-    def draw_left(self, context):
-        layout = self.layout
-
-        # Active Tool
-        # -----------
-        from .space_toolsystem_common import ToolSelectPanelHelper
-        tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
-        tool_space_type = 'VIEW_3D' if tool is None else tool.space_type
-        tool_mode = context.mode if tool is None else tool.mode
-
-        # Object Mode Options
-        # -------------------
-
-        # Example of how tool_settings can be accessed as pop-overs.
-
-        # TODO(campbell): editing options should be after active tool options
-        # (obviously separated for from the users POV)
-        draw_fn = getattr(getattr(_draw_left_context_mode, tool_space_type, None), tool_mode, None)
-        if draw_fn is not None:
-            draw_fn(context, layout, tool)
-
-        if tool_space_type == 'VIEW_3D':
-            # Note: general mode options should be added to 'draw_right'.
-            if tool_mode == 'SCULPT':
-                if (tool is not None) and tool.has_datablock:
-                    layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
-            elif tool_mode == 'PAINT_VERTEX':
-                if (tool is not None) and tool.has_datablock:
-                    layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
-            elif tool_mode == 'PAINT_WEIGHT':
-                if (tool is not None) and tool.has_datablock:
-                    layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
-            elif tool_mode == 'PAINT_TEXTURE':
-                if (tool is not None) and tool.has_datablock:
-                    layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
-            elif tool_mode == 'EDIT_ARMATURE':
-                pass
-            elif tool_mode == 'EDIT_CURVE':
-                pass
-            elif tool_mode == 'EDIT_MESH':
-                pass
-            elif tool_mode == 'POSE':
-                pass
-            elif tool_mode == 'PARTICLE':
-                # Disable, only shows "Brush" panel, which is already in the top-bar.
-                # if tool.has_datablock:
-                #     layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
-                pass
-            elif tool_mode == 'PAINT_GPENCIL':
-                if (tool is not None) and tool.has_datablock:
-                    layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_paint", category="")
-            elif tool_mode == 'SCULPT_GPENCIL':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_sculpt", category="")
-            elif tool_mode == 'WEIGHT_GPENCIL':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_weight", category="")
-        elif tool_space_type == 'IMAGE_EDITOR':
-            if tool_mode == 'PAINT':
-                if (tool is not None) and tool.has_datablock:
-                    layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common_2d", category="")
-            elif context.uv_sculpt_object is not None:
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".uv_sculpt", category="")
-
-    def draw_right(self, context):
-        layout = self.layout
-
-        # Active Tool
-        # -----------
-        from .space_toolsystem_common import ToolSelectPanelHelper
-        tool = ToolSelectPanelHelper.tool_active_from_context(context)
-        tool_space_type = 'VIEW_3D' if tool is None else tool.space_type
-        tool_mode = context.mode if tool is None else tool.mode
-
-        if tool_space_type == 'VIEW_3D':
-            if tool_mode == 'SCULPT':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".sculpt_mode", category="")
-            elif tool_mode == 'PAINT_VERTEX':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".vertexpaint", category="")
-            elif tool_mode == 'PAINT_WEIGHT':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".weightpaint", category="")
-            elif tool_mode == 'PAINT_TEXTURE':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".imagepaint", category="")
-            elif tool_mode == 'EDIT_TEXT':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".text_edit", category="")
-            elif tool_mode == 'EDIT_ARMATURE':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".armature_edit", category="")
-            elif tool_mode == 'EDIT_METABALL':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mball_edit", category="")
-            elif tool_mode == 'EDIT_LATTICE':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".lattice_edit", category="")
-            elif tool_mode == 'EDIT_CURVE':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".curve_edit", category="")
-            elif tool_mode == 'EDIT_MESH':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mesh_edit", category="")
-            elif tool_mode == 'POSE':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".posemode", category="")
-            elif tool_mode == 'PARTICLE':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="")
-            elif tool_mode == 'OBJECT':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="")
-            elif tool_mode in {'PAINT_GPENCIL', 'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
-                # Grease pencil layer.
-                gpl = context.active_gpencil_layer
-                if gpl and gpl.info is not None:
-                    text = gpl.info
-                    maxw = 25
-                    if len(text) > maxw:
-                        text = text[:maxw - 5] + '..' + text[-3:]
-                else:
-                    text = ""
-
-                layout.label(text="Layer:")
-                sub = layout.row()
-                sub.ui_units_x = 8
-                sub.popover(
-                    panel="TOPBAR_PT_gpencil_layers",
-                    text=text,
-                )
-        elif tool_space_type == 'IMAGE_EDITOR':
-            if tool_mode == 'PAINT':
-                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".imagepaint_2d", category="")
-
-
-class _draw_left_context_mode:
-    class VIEW_3D:
-        @staticmethod
-        def SCULPT(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-
-            paint = context.tool_settings.sculpt
-            layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
-
-            brush = paint.brush
-            if brush is None:
-                return
-
-            from .properties_paint_common import (
-                brush_basic_sculpt_settings,
-            )
-            brush_basic_sculpt_settings(layout, context, brush, compact=True)
-
-        @staticmethod
-        def PAINT_TEXTURE(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-
-            paint = context.tool_settings.image_paint
-            layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
-
-            brush = paint.brush
-            if brush is None:
-                return
-
-            from .properties_paint_common import (
-                UnifiedPaintPanel,
-                brush_basic_texpaint_settings,
-            )
-            capabilities = brush.image_paint_capabilities
-            if capabilities.has_color:
-                UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
-            brush_basic_texpaint_settings(layout, context, brush, compact=True)
-
-        @staticmethod
-        def PAINT_VERTEX(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-
-            paint = context.tool_settings.vertex_paint
-            layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
-
-            brush = paint.brush
-            if brush is None:
-                return
-
-            from .properties_paint_common import (
-                UnifiedPaintPanel,
-                brush_basic_vpaint_settings,
-            )
-            capabilities = brush.vertex_paint_capabilities
-            if capabilities.has_color:
-                UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
-            brush_basic_vpaint_settings(layout, context, brush, compact=True)
-
-        @staticmethod
-        def PAINT_WEIGHT(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-
-            paint = context.tool_settings.weight_paint
-            layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
-            brush = paint.brush
-            if brush is None:
-                return
-
-            from .properties_paint_common import brush_basic_wpaint_settings
-            brush_basic_wpaint_settings(layout, context, brush, compact=True)
-
-        @staticmethod
-        def PAINT_GPENCIL(context, layout, tool):
-            if tool is None:
-                return
-
-            # is_paint = True
-            # FIXME: tools must use their own UI drawing!
-            if tool.idname in {"builtin.line", "builtin.box", "builtin.circle", "builtin.arc", "builtin.curve"}:
-                # is_paint = False
-                pass
-            elif tool.idname == "Cutter":
-                row = layout.row(align=True)
-                row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
-                return
-            elif not tool.has_datablock:
-                return
-
-            paint = context.tool_settings.gpencil_paint
-            brush = paint.brush
-            if brush is None:
-                return
-
-            gp_settings = brush.gpencil_settings
-
-            def draw_color_selector():
-                ma = gp_settings.material
-                row = layout.row(align=True)
-                if not gp_settings.use_material_pin:
-                    ma = context.object.active_material
-                icon_id = 0
-                if ma:
-                    icon_id = ma.id_data.preview.icon_id
-                    txt_ma = ma.name
-                    maxw = 25
-                    if len(txt_ma) > maxw:
-                        txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:]
-                else:
-                    txt_ma = ""
-
-                row.label(text="Material:")
-                sub = row.row()
-                sub.ui_units_x = 8
-                sub.popover(
-                    panel="TOPBAR_PT_gpencil_materials",
-                    text=txt_ma,
-                    icon_value=icon_id,
-                )
-
-                row.prop(gp_settings, "use_material_pin", text="")
-
-            row = layout.row(align=True)
-            tool_settings = context.scene.tool_settings
-            settings = tool_settings.gpencil_paint
-            row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
-
-            if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}:
-                draw_color_selector()
-
-            from .properties_paint_common import (
-                brush_basic_gpencil_paint_settings,
-            )
-            brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
-
-            # FIXME: tools must use their own UI drawing!
-            if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}:
-                settings = context.tool_settings.gpencil_sculpt
-                row = layout.row(align=True)
-                row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
-                sub = row.row(align=True)
-                sub.active = settings.use_thickness_curve
-                sub.popover(
-                    panel="TOPBAR_PT_gpencil_primitive",
-                    text="Thickness Profile",
-                )
-
-            if brush.gpencil_tool == 'FILL':
-                settings = context.tool_settings.gpencil_sculpt
-                row = layout.row(align=True)
-                sub = row.row(align=True)
-                sub.popover(
-                    panel="TOPBAR_PT_gpencil_fill",
-                    text="Fill Options",
-                )
-
-        @staticmethod
-        def SCULPT_GPENCIL(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-            tool_settings = context.tool_settings
-            settings = tool_settings.gpencil_sculpt
-            brush = settings.brush
-
-            from .properties_paint_common import (
-                brush_basic_gpencil_sculpt_settings,
-            )
-            brush_basic_gpencil_sculpt_settings(layout, context, brush, compact=True)
-
-        @staticmethod
-        def WEIGHT_GPENCIL(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-            tool_settings = context.tool_settings
-            settings = tool_settings.gpencil_sculpt
-            brush = settings.brush
-
-            from .properties_paint_common import (
-                brush_basic_gpencil_weight_settings,
-            )
-            brush_basic_gpencil_weight_settings(layout, context, brush, compact=True)
-
-        @staticmethod
-        def PARTICLE(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-
-            # See: 'VIEW3D_PT_tools_brush', basically a duplicate
-            settings = context.tool_settings.particle_edit
-            brush = settings.brush
-            tool = settings.tool
-            if tool != 'NONE':
-                layout.prop(brush, "size", slider=True)
-                if tool == 'ADD':
-                    layout.prop(brush, "count")
-
-                    layout.prop(settings, "use_default_interpolate")
-                    layout.prop(brush, "steps", slider=True)
-                    layout.prop(settings, "default_key_count", slider=True)
-                else:
-                    layout.prop(brush, "strength", slider=True)
-
-                    if tool == 'LENGTH':
-                        layout.row().prop(brush, "length_mode", expand=True)
-                    elif tool == 'PUFF':
-                        layout.row().prop(brush, "puff_mode", expand=True)
-                        layout.prop(brush, "use_puff_volume")
-                    elif tool == 'COMB':
-                        row = layout.row()
-                        row.active = settings.is_editable
-                        row.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
-                        sub = row.row(align=True)
-                        sub.active = settings.use_emitter_deflect
-                        sub.prop(settings, "emitter_distance", text="Distance")
-
-    class IMAGE_EDITOR:
-        @staticmethod
-        def VIEW(context, layout, tool):
-            tool_settings = context.tool_settings
-            if tool_settings.use_uv_sculpt:
-                if context.mode == 'EDIT_MESH':
-                    uv_sculpt = tool_settings.uv_sculpt
-                    brush = uv_sculpt.brush
-                    if brush:
-                        from .properties_paint_common import UnifiedPaintPanel
-
-                        row = layout.row(align=True)
-                        UnifiedPaintPanel.prop_unified_size(row, context, brush, "size", slider=True)
-                        UnifiedPaintPanel.prop_unified_size(row, context, brush, "use_pressure_size", text="")
-
-                        row = layout.row(align=True)
-                        UnifiedPaintPanel.prop_unified_strength(row, context, brush, "strength", slider=True)
-                        UnifiedPaintPanel.prop_unified_strength(row, context, brush, "use_pressure_strength", text="")
-
-        @staticmethod
-        def PAINT(context, layout, tool):
-            if (tool is None) or (not tool.has_datablock):
-                return
-
-            paint = context.tool_settings.image_paint
-            layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
-
-            brush = paint.brush
-            if brush is None:
-                return
-
-            from .properties_paint_common import (
-                UnifiedPaintPanel,
-                brush_basic_texpaint_settings,
-            )
-            capabilities = brush.image_paint_capabilities
-            if capabilities.has_color:
-                UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
-            brush_basic_texpaint_settings(layout, context, brush, compact=True)
-
-
 class TOPBAR_PT_gpencil_layers(Panel):
     bl_space_type = 'VIEW_3D'
     bl_region_type = 'HEADER'
@@ -858,7 +465,6 @@ class TOPBAR_MT_window(Menu):
 
         layout.separator()
 
-        layout.prop(context.screen, "show_topbar")
         layout.prop(context.screen, "show_statusbar")
 
         layout.separator()
@@ -1053,7 +659,7 @@ class TOPBAR_PT_gpencil_fill(Panel):
 # Only a popover
 class TOPBAR_PT_name(Panel):
     bl_space_type = 'TOPBAR'  # dummy
-    bl_region_type = 'WINDOW'
+    bl_region_type = 'HEADER'
     bl_label = "Rename Active Item"
     bl_ui_units_x = 14
 
@@ -1120,7 +726,6 @@ class TOPBAR_PT_name(Panel):
 
 classes = (
     TOPBAR_HT_upper_bar,
-    TOPBAR_HT_lower_bar,
     TOPBAR_MT_file_context_menu,
     TOPBAR_MT_workspace_menu,
     TOPBAR_MT_editor_menus,
@@ -1139,7 +744,6 @@ classes = (
     TOPBAR_PT_gpencil_layers,
     TOPBAR_PT_gpencil_primitive,
     TOPBAR_PT_gpencil_fill,
-    TOPBAR_PT_name,
 )
 
 if __name__ == "__main__":  # only for live edit.
index d16a50c..6cdc7dd 100644 (file)
@@ -34,12 +34,15 @@ from .properties_grease_pencil_common import (
 from bpy.app.translations import contexts as i18n_contexts
 
 
-class VIEW3D_HT_header(Header):
+class VIEW3D_HT_tool_header(Header):
     bl_space_type = 'VIEW_3D'
+    bl_region_type = "TOOL_HEADER"
 
     def draw(self, context):
         layout = self.layout
 
+        layout.row(align=True).template_header()
+
         view = context.space_data
         shading = view.shading
         # mode_string = context.mode
@@ -47,85 +50,13 @@ class VIEW3D_HT_header(Header):
         overlay = view.overlay
         tool_settings = context.tool_settings
 
-        row = layout.row(align=True)
-        row.template_header()
-
         object_mode = 'OBJECT' if obj is None else obj.mode
         has_pose_mode = (
             (object_mode == 'POSE') or
             (object_mode == 'WEIGHT_PAINT' and context.pose_object is not None)
         )
 
-        # Note: This is actually deadly in case enum_items have to be dynamically generated
-        #       (because internal RNA array iterator will free everything immediately...).
-        # XXX This is an RNA internal issue, not sure how to fix it.
-        # Note: Tried to add an accessor to get translated UI strings instead of manual call
-        #       to pgettext_iface below, but this fails because translated enumitems
-        #       are always dynamically allocated.
-        act_mode_item = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode]
-        act_mode_i18n_context = bpy.types.Object.bl_rna.properties["mode"].translation_context
-
-        row.separator()
-
-        sub = row.row()
-        sub.ui_units_x = 5.5
-        sub.operator_menu_enum("object.mode_set", "mode",
-                               text=bpy.app.translations.pgettext_iface(act_mode_item.name, act_mode_i18n_context),
-                               icon=act_mode_item.icon)
-        del act_mode_item
-
-        layout.template_header_3D_mode()
-
-        # Contains buttons like Mode, Pivot, Layer, Mesh Select Mode...
-        if obj:
-            # Particle edit
-            if object_mode == 'PARTICLE_EDIT':
-                row = layout.row()
-                row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True)
-
-        # Grease Pencil
-        if obj and obj.type == 'GPENCIL' and context.gpencil_data:
-            gpd = context.gpencil_data
-
-            if gpd.is_stroke_paint_mode:
-                row = layout.row()
-                sub = row.row(align=True)
-                sub.prop(tool_settings, "use_gpencil_draw_onback", text="", icon='MOD_OPACITY')
-                sub.separator(factor=0.4)
-                sub.prop(tool_settings, "use_gpencil_weight_data_add", text="", icon='WPAINT_HLT')
-                sub.separator(factor=0.4)
-                sub.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
-
-            if gpd.use_stroke_edit_mode:
-                row = layout.row(align=True)
-                row.prop(tool_settings, "gpencil_selectmode", text="", expand=True)
-
-            if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
-                row = layout.row(align=True)
-
-                if gpd.is_stroke_sculpt_mode:
-                    row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
-                    row.separator()
-
-                row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING')
-
-                sub = row.row(align=True)
-                sub.active = gpd.use_multiedit
-                sub.popover(
-                    panel="VIEW3D_PT_gpencil_multi_frame",
-                    text="Multiframe",
-                )
-
-            if gpd.use_stroke_edit_mode:
-                row = layout.row(align=True)
-                row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
-
-                row.popover(
-                    panel="VIEW3D_PT_tools_grease_pencil_interpolate",
-                    text="Interpolate",
-                )
-
-        VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
+        self.draw_tool_settings(context)
 
         layout.separator_spacer()
 
@@ -257,6 +188,428 @@ class VIEW3D_HT_header(Header):
 
         layout.separator_spacer()
 
+        self.draw_mode_settings(context)
+
+    def draw_tool_settings(self, context):
+        layout = self.layout
+
+        # Active Tool
+        # -----------
+        from .space_toolsystem_common import ToolSelectPanelHelper
+        tool = ToolSelectPanelHelper.draw_active_tool_header(context, layout)
+        tool_mode = context.mode if tool is None else tool.mode
+
+        # Object Mode Options
+        # -------------------
+
+        # Example of how tool_settings can be accessed as pop-overs.
+
+        # TODO(campbell): editing options should be after active tool options
+        # (obviously separated for from the users POV)
+        draw_fn = getattr(_draw_tool_settings_context_mode, tool_mode, None)
+        if draw_fn is not None:
+            draw_fn(context, layout, tool)
+
+        # Note: general mode options should be added to 'draw_mode_settings'.
+        if tool_mode == 'SCULPT':
+            if (tool is not None) and tool.has_datablock:
+                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+        elif tool_mode == 'PAINT_VERTEX':
+            if (tool is not None) and tool.has_datablock:
+                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+        elif tool_mode == 'PAINT_WEIGHT':
+            if (tool is not None) and tool.has_datablock:
+                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+        elif tool_mode == 'PAINT_TEXTURE':
+            if (tool is not None) and tool.has_datablock:
+                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+        elif tool_mode == 'EDIT_ARMATURE':
+            pass
+        elif tool_mode == 'EDIT_CURVE':
+            pass
+        elif tool_mode == 'EDIT_MESH':
+            pass
+        elif tool_mode == 'POSE':
+            pass
+        elif tool_mode == 'PARTICLE':
+            # Disable, only shows "Brush" panel, which is already in the top-bar.
+            # if tool.has_datablock:
+            #     layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".paint_common", category="")
+            pass
+        elif tool_mode == 'PAINT_GPENCIL':
+            if (tool is not None) and tool.has_datablock:
+                layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_paint", category="")
+        elif tool_mode == 'SCULPT_GPENCIL':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_sculpt", category="")
+        elif tool_mode == 'WEIGHT_GPENCIL':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".greasepencil_weight", category="")
+
+    def draw_mode_settings(self, context):
+        layout = self.layout
+
+        # Active Tool
+        # -----------
+        from .space_toolsystem_common import ToolSelectPanelHelper
+        tool = ToolSelectPanelHelper.tool_active_from_context(context)
+        tool_mode = context.mode if tool is None else tool.mode
+
+        if tool_mode == 'SCULPT':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".sculpt_mode", category="")
+        elif tool_mode == 'PAINT_VERTEX':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".vertexpaint", category="")
+        elif tool_mode == 'PAINT_WEIGHT':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".weightpaint", category="")
+        elif tool_mode == 'PAINT_TEXTURE':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".imagepaint", category="")
+        elif tool_mode == 'EDIT_TEXT':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".text_edit", category="")
+        elif tool_mode == 'EDIT_ARMATURE':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".armature_edit", category="")
+        elif tool_mode == 'EDIT_METABALL':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mball_edit", category="")
+        elif tool_mode == 'EDIT_LATTICE':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".lattice_edit", category="")
+        elif tool_mode == 'EDIT_CURVE':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".curve_edit", category="")
+        elif tool_mode == 'EDIT_MESH':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".mesh_edit", category="")
+        elif tool_mode == 'POSE':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".posemode", category="")
+        elif tool_mode == 'PARTICLE':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".particlemode", category="")
+        elif tool_mode == 'OBJECT':
+            layout.popover_group(space_type='PROPERTIES', region_type='WINDOW', context=".objectmode", category="")
+        elif tool_mode in {'PAINT_GPENCIL', 'EDIT_GPENCIL', 'SCULPT_GPENCIL', 'WEIGHT_GPENCIL'}:
+            # Grease pencil layer.
+            gpl = context.active_gpencil_layer
+            if gpl and gpl.info is not None:
+                text = gpl.info
+                maxw = 25
+                if len(text) > maxw:
+                    text = text[:maxw - 5] + '..' + text[-3:]
+            else:
+                text = ""
+
+            layout.label(text="Layer:")
+            sub = layout.row()
+            sub.ui_units_x = 8
+            sub.popover(
+                panel="TOPBAR_PT_gpencil_layers",
+                text=text,
+            )
+
+
+class _draw_tool_settings_context_mode:
+    @staticmethod
+    def SCULPT(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+
+        paint = context.tool_settings.sculpt
+        layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
+
+        brush = paint.brush
+        if brush is None:
+            return
+
+        from .properties_paint_common import (
+            brush_basic_sculpt_settings,
+        )
+        brush_basic_sculpt_settings(layout, context, brush, compact=True)
+
+    @staticmethod
+    def PAINT_TEXTURE(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+
+        paint = context.tool_settings.image_paint
+        layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
+
+        brush = paint.brush
+        if brush is None:
+            return
+
+        from .properties_paint_common import (
+            UnifiedPaintPanel,
+            brush_basic_texpaint_settings,
+        )
+        capabilities = brush.image_paint_capabilities
+        if capabilities.has_color:
+            UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
+        brush_basic_texpaint_settings(layout, context, brush, compact=True)
+
+    @staticmethod
+    def PAINT_VERTEX(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+
+        paint = context.tool_settings.vertex_paint
+        layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
+
+        brush = paint.brush
+        if brush is None:
+            return
+
+        from .properties_paint_common import (
+            UnifiedPaintPanel,
+            brush_basic_vpaint_settings,
+        )
+        capabilities = brush.vertex_paint_capabilities
+        if capabilities.has_color:
+            UnifiedPaintPanel.prop_unified_color(layout, context, brush, "color", text="")
+        brush_basic_vpaint_settings(layout, context, brush, compact=True)
+
+    @staticmethod
+    def PAINT_WEIGHT(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+
+        paint = context.tool_settings.weight_paint
+        layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
+        brush = paint.brush
+        if brush is None:
+            return
+
+        from .properties_paint_common import brush_basic_wpaint_settings
+        brush_basic_wpaint_settings(layout, context, brush, compact=True)
+
+    @staticmethod
+    def PAINT_GPENCIL(context, layout, tool):
+        if tool is None:
+            return
+
+        # is_paint = True
+        # FIXME: tools must use their own UI drawing!
+        if tool.idname in {"builtin.line", "builtin.box", "builtin.circle", "builtin.arc", "builtin.curve"}:
+            # is_paint = False
+            pass
+        elif tool.idname == "Cutter":
+            row = layout.row(align=True)
+            row.prop(context.tool_settings.gpencil_sculpt, "intersection_threshold")
+            return
+        elif not tool.has_datablock:
+            return
+
+        paint = context.tool_settings.gpencil_paint
+        brush = paint.brush
+        if brush is None:
+            return
+
+        gp_settings = brush.gpencil_settings
+
+        def draw_color_selector():
+            ma = gp_settings.material
+            row = layout.row(align=True)
+            if not gp_settings.use_material_pin:
+                ma = context.object.active_material
+            icon_id = 0
+            if ma:
+                icon_id = ma.id_data.preview.icon_id
+                txt_ma = ma.name
+                maxw = 25
+                if len(txt_ma) > maxw:
+                    txt_ma = txt_ma[:maxw - 5] + '..' + txt_ma[-3:]
+            else:
+                txt_ma = ""
+
+            row.label(text="Material:")
+            sub = row.row()
+            sub.ui_units_x = 8
+            sub.popover(
+                panel="TOPBAR_PT_gpencil_materials",
+                text=txt_ma,
+                icon_value=icon_id,
+            )
+
+            row.prop(gp_settings, "use_material_pin", text="")
+
+        row = layout.row(align=True)
+        tool_settings = context.scene.tool_settings
+        settings = tool_settings.gpencil_paint
+        row.template_ID_preview(settings, "brush", rows=3, cols=8, hide_buttons=True)
+
+        if context.object and brush.gpencil_tool in {'FILL', 'DRAW'}:
+            draw_color_selector()
+
+        from .properties_paint_common import (
+            brush_basic_gpencil_paint_settings,
+        )
+        brush_basic_gpencil_paint_settings(layout, context, brush, compact=True)
+
+        # FIXME: tools must use their own UI drawing!
+        if tool.idname in {"builtin.arc", "builtin.curve", "builtin.line", "builtin.box", "builtin.circle"}:
+            settings = context.tool_settings.gpencil_sculpt
+            row = layout.row(align=True)
+            row.prop(settings, "use_thickness_curve", text="", icon='CURVE_DATA')
+            sub = row.row(align=True)
+            sub.active = settings.use_thickness_curve
+            sub.popover(
+                panel="TOPBAR_PT_gpencil_primitive",
+                text="Thickness Profile",
+            )
+
+        if brush.gpencil_tool == 'FILL':
+            settings = context.tool_settings.gpencil_sculpt
+            row = layout.row(align=True)
+            sub = row.row(align=True)
+            sub.popover(
+                panel="TOPBAR_PT_gpencil_fill",
+                text="Fill Options",
+            )
+
+    @staticmethod
+    def SCULPT_GPENCIL(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+        tool_settings = context.tool_settings
+        settings = tool_settings.gpencil_sculpt
+        brush = settings.brush
+
+        from .properties_paint_common import (
+            brush_basic_gpencil_sculpt_settings,
+        )
+        brush_basic_gpencil_sculpt_settings(layout, context, brush, compact=True)
+
+    @staticmethod
+    def WEIGHT_GPENCIL(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+        tool_settings = context.tool_settings
+        settings = tool_settings.gpencil_sculpt
+        brush = settings.brush
+
+        from .properties_paint_common import (
+            brush_basic_gpencil_weight_settings,
+        )
+        brush_basic_gpencil_weight_settings(layout, context, brush, compact=True)
+
+    @staticmethod
+    def PARTICLE(context, layout, tool):
+        if (tool is None) or (not tool.has_datablock):
+            return
+
+        # See: 'VIEW3D_PT_tools_brush', basically a duplicate
+        settings = context.tool_settings.particle_edit
+        brush = settings.brush
+        tool = settings.tool
+        if tool != 'NONE':
+            layout.prop(brush, "size", slider=True)
+            if tool == 'ADD':
+                layout.prop(brush, "count")
+
+                layout.prop(settings, "use_default_interpolate")
+                layout.prop(brush, "steps", slider=True)
+                layout.prop(settings, "default_key_count", slider=True)
+            else:
+                layout.prop(brush, "strength", slider=True)
+
+                if tool == 'LENGTH':
+                    layout.row().prop(brush, "length_mode", expand=True)
+                elif tool == 'PUFF':
+                    layout.row().prop(brush, "puff_mode", expand=True)
+                    layout.prop(brush, "use_puff_volume")
+                elif tool == 'COMB':
+                    row = layout.row()
+                    row.active = settings.is_editable
+                    row.prop(settings, "use_emitter_deflect", text="Deflect Emitter")
+                    sub = row.row(align=True)
+                    sub.active = settings.use_emitter_deflect
+                    sub.prop(settings, "emitter_distance", text="Distance")
+
+
+class VIEW3D_HT_header(Header):
+    bl_space_type = 'VIEW_3D'
+
+    def draw(self, context):
+        layout = self.layout
+
+        tool_settings = context.tool_settings
+        view = context.space_data
+        shading = view.shading
+        # mode_string = context.mode
+        obj = context.active_object
+
+        if not view.show_region_tool_header:
+            layout.row(align=True).template_header()
+
+        row = layout.row(align=True)
+        object_mode = 'OBJECT' if obj is None else obj.mode
+
+        # Note: This is actually deadly in case enum_items have to be dynamically generated
+        #       (because internal RNA array iterator will free everything immediately...).
+        # XXX This is an RNA internal issue, not sure how to fix it.
+        # Note: Tried to add an accessor to get translated UI strings instead of manual call
+        #       to pgettext_iface below, but this fails because translated enumitems
+        #       are always dynamically allocated.
+        act_mode_item = bpy.types.Object.bl_rna.properties["mode"].enum_items[object_mode]
+        act_mode_i18n_context = bpy.types.Object.bl_rna.properties["mode"].translation_context
+
+        sub = row.row(align=True)
+        sub.ui_units_x = 5.5
+        sub.operator_menu_enum(
+            "object.mode_set", "mode",
+            text=bpy.app.translations.pgettext_iface(act_mode_item.name, act_mode_i18n_context),
+            icon=act_mode_item.icon,
+        )
+        del act_mode_item
+
+        layout.template_header_3D_mode()
+
+        # Contains buttons like Mode, Pivot, Layer, Mesh Select Mode...
+        if obj:
+            # Particle edit
+            if object_mode == 'PARTICLE_EDIT':
+                row = layout.row()
+                row.prop(tool_settings.particle_edit, "select_mode", text="", expand=True)
+
+        # Grease Pencil
+        if obj and obj.type == 'GPENCIL' and context.gpencil_data:
+            gpd = context.gpencil_data
+
+            if gpd.is_stroke_paint_mode:
+                row = layout.row()
+                sub = row.row(align=True)
+                sub.prop(tool_settings, "use_gpencil_draw_onback", text="", icon='MOD_OPACITY')
+                sub.separator(factor=0.4)
+                sub.prop(tool_settings, "use_gpencil_weight_data_add", text="", icon='WPAINT_HLT')
+                sub.separator(factor=0.4)
+                sub.prop(tool_settings, "use_gpencil_draw_additive", text="", icon='FREEZE')
+
+            if gpd.use_stroke_edit_mode:
+                row = layout.row(align=True)
+                row.prop(tool_settings, "gpencil_selectmode", text="", expand=True)
+
+            if gpd.use_stroke_edit_mode or gpd.is_stroke_sculpt_mode or gpd.is_stroke_weight_mode:
+                row = layout.row(align=True)
+
+                if gpd.is_stroke_sculpt_mode:
+                    row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
+                    row.separator()
+
+                row.prop(gpd, "use_multiedit", text="", icon='GP_MULTIFRAME_EDITING')
+
+                sub = row.row(align=True)
+                sub.active = gpd.use_multiedit
+                sub.popover(
+                    panel="VIEW3D_PT_gpencil_multi_frame",
+                    text="Multiframe",
+                )
+
+            if gpd.use_stroke_edit_mode:
+                row = layout.row(align=True)
+                row.prop(tool_settings.gpencil_sculpt, "use_select_mask", text="")
+
+                row.popover(
+                    panel="VIEW3D_PT_tools_grease_pencil_interpolate",
+                    text="Interpolate",
+                )
+
+        overlay = view.overlay
+
+        VIEW3D_MT_editor_menus.draw_collapsible(context, layout)
+
+        layout.separator_spacer()
+
         # Viewport Settings
         layout.popover(
             panel="VIEW3D_PT_object_type_visibility",
@@ -5910,6 +6263,7 @@ class TOPBAR_PT_gpencil_materials(GreasePencilMaterialsPanel, Panel):
 
 classes = (
     VIEW3D_HT_header,
+    VIEW3D_HT_tool_header,
     VIEW3D_MT_editor_menus,
     VIEW3D_MT_transform,
     VIEW3D_MT_transform_base,
index 9fa70d3..df018f7 100644 (file)
@@ -868,7 +868,7 @@ void BKE_screen_header_alignment_reset(bScreen *screen)
   int alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
   for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
     for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
-      if (ar->regiontype == RGN_TYPE_HEADER) {
+      if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
         if (ELEM(sa->spacetype, SPACE_FILE, SPACE_USERPREF, SPACE_OUTLINER, SPACE_PROPERTIES)) {
           ar->alignment = RGN_ALIGN_TOP;
           continue;
index 523e0b3..e43553c 100644 (file)
@@ -591,17 +591,25 @@ static void do_versions_remove_region(ListBase *regionbase, int regiontype)
   }
 }
 
-static ARegion *do_versions_find_region(ListBase *regionbase, int regiontype)
+static ARegion *do_versions_find_region_or_null(ListBase *regionbase, int regiontype)
 {
   for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
     if (ar->regiontype == regiontype) {
       return ar;
     }
   }
-  BLI_assert(!"Did not find expected region in versioning");
   return NULL;
 }
 
+static ARegion *do_versions_find_region(ListBase *regionbase, int regiontype)
+{
+  ARegion *ar = do_versions_find_region_or_null(regionbase, regiontype);
+  if (ar == NULL) {
+    BLI_assert(!"Did not find expected region in versioning");
+  }
+  return ar;
+}
+
 static ARegion *do_versions_add_region(int regiontype, const char *name)
 {
   ARegion *ar = MEM_callocN(sizeof(ARegion), name);
@@ -3130,6 +3138,27 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
     }
   }
 
+  /* Keep un-versioned until we're finished adding space types. */
+  {
+    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) {
+          ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+          /* All spaces that use tools must be eventually added. */
+          if (ELEM(sl->spacetype, SPACE_VIEW3D, SPACE_IMAGE) &&
+              (do_versions_find_region_or_null(regionbase, RGN_TYPE_TOOL_HEADER) == NULL)) {
+            /* Add tool header. */
+            ARegion *ar = do_versions_add_region(RGN_TYPE_TOOL_HEADER, "tool header");
+            ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+
+            ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER);
+            BLI_insertlinkbefore(regionbase, ar_header, ar);
+          }
+        }
+      }
+    }
+  }
+
   {
     if (!DNA_struct_elem_find(fd->filesdna, "bSplineIKConstraint", "short", "yScaleMode")) {
       for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
index 04bbbbd..b4349ff 100644 (file)
@@ -131,10 +131,21 @@ bool ED_region_snap_size_apply(struct ARegion *ar, int snap_flag);
 void ED_region_do_msg_notify_tag_redraw(struct bContext *C,
                                         struct wmMsgSubscribeKey *msg_key,
                                         struct wmMsgSubscribeValue *msg_val);
+void ED_area_do_msg_notify_tag_redraw(struct bContext *C,
+                                      struct wmMsgSubscribeKey *msg_key,
+                                      struct wmMsgSubscribeValue *msg_val);
 void ED_area_do_msg_notify_tag_refresh(struct bContext *C,
                                        struct wmMsgSubscribeKey *msg_key,
                                        struct wmMsgSubscribeValue *msg_val);
 
+void ED_area_do_mgs_subscribe_for_tool_header(const struct bContext *C,
+                                              struct WorkSpace *workspace,
+                                              struct Scene *scene,
+                                              struct bScreen *screen,
+                                              struct ScrArea *sa,
+                                              struct ARegion *ar,
+                                              struct wmMsgBus *mbus);
+
 /* message bus */
 void ED_region_message_subscribe(struct bContext *C,
                                  struct WorkSpace *workspace,
index c8800f4..b6d9863 100644 (file)
@@ -1064,7 +1064,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but)
     if (!ar) {
       /* skip */
     }
-    else if (ar->regiontype == RGN_TYPE_HEADER) {
+    else if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
       uiItemMenuF(layout, IFACE_("Header"), ICON_NONE, ED_screens_header_tools_menu_create, NULL);
     }
     else if (ar->regiontype == RGN_TYPE_NAV_BAR) {
index e9914ce..72aa992 100644 (file)
@@ -1778,7 +1778,11 @@ static bool ui_but_drag_init(bContext *C,
 
       /* 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, RGN_TYPE_FOOTER)) {
+      if (ELEM(data->region->regiontype,
+               RGN_TYPE_NAV_BAR,
+               RGN_TYPE_HEADER,
+               RGN_TYPE_TOOL_HEADER,
+               RGN_TYPE_FOOTER)) {
         int lock_axis = -1;
         if (ELEM(data->region->alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT)) {
           lock_axis = 0;
index d364bf7..b97cbcd 100644 (file)
@@ -279,7 +279,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
       ScrArea *sa = CTX_wm_area(C);
       ARegion *ar = CTX_wm_region(C);
       if (sa && ar) {
-        if (ar->regiontype == RGN_TYPE_HEADER) {
+        if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
           if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
             UI_block_direction_set(block, UI_DIR_UP);
             UI_block_order_flip(block);
index bbf3df6..110c882 100644 (file)
@@ -187,7 +187,7 @@ static uiBlock *ui_block_func_POPOVER(bContext *C, uiPopupBlockHandle *handle, v
       }
       /* Prefer popover from header to be positioned into the editor. */
       else if (sa && ar) {
-        if (ar->regiontype == RGN_TYPE_HEADER) {
+        if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
           if (ED_area_header_alignment(sa) == RGN_ALIGN_BOTTOM) {
             UI_block_direction_set(block, UI_DIR_UP | UI_DIR_CENTER_X);
           }
index 76d82b9..bbff2c1 100644 (file)
@@ -127,11 +127,8 @@ static void template_add_button_search_menu(const bContext *C,
 
   if (use_previews) {
     ARegion *region = CTX_wm_region(C);
-    ScrArea *area = CTX_wm_area(C);
-    /* XXX ugly top-bar exception */
-    const bool use_big_size = (
-        /* silly check, could be more generic */
-        (region->regiontype != RGN_TYPE_HEADER) && (area->spacetype != SPACE_TOPBAR));
+    /* Ugly tool header exception. */
+    const bool use_big_size = (region->regiontype != RGN_TYPE_TOOL_HEADER);
     /* Ugly exception for screens here,
      * drawing their preview in icon size looks ugly/useless */
     const bool use_preview_icon = use_big_size || (id && (GS(id->name) != ID_SCR));
index 1aa54bc..250a417 100644 (file)
@@ -421,17 +421,18 @@ static void region_draw_status_text(ScrArea *sa, ARegion *ar)
   BLF_draw(fontid, ar->headerstr, BLF_DRAW_STR_DUMMY_MAX);
 }
 
-/* Follow wmMsgNotifyFn spec */
-void ED_region_do_msg_notify_tag_redraw(bContext *UNUSED(C),
-                                        wmMsgSubscribeKey *UNUSED(msg_key),
-                                        wmMsgSubscribeValue *msg_val)
+void ED_region_do_msg_notify_tag_redraw(
+    /* Follow wmMsgNotifyFn spec */
+    bContext *UNUSED(C),
+    wmMsgSubscribeKey *UNUSED(msg_key),
+    wmMsgSubscribeValue *msg_val)
 {
   ARegion *ar = msg_val->owner;
   ED_region_tag_redraw(ar);
 
   /* This avoids _many_ situations where header/properties control display settings.
    * the common case is space properties in the header */
-  if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_UI)) {
+  if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_UI)) {
     while (ar && ar->prev) {
       ar = ar->prev;
     }
@@ -442,15 +443,48 @@ void ED_region_do_msg_notify_tag_redraw(bContext *UNUSED(C),
     }
   }
 }
-/* Follow wmMsgNotifyFn spec */
-void ED_area_do_msg_notify_tag_refresh(bContext *UNUSED(C),
-                                       wmMsgSubscribeKey *UNUSED(msg_key),
-                                       wmMsgSubscribeValue *msg_val)
+/**
+ * Use #ED_region_do_msg_notify_tag_redraw where possible, this draws too much typically.
+ */
+void ED_area_do_msg_notify_tag_redraw(
+    /* Follow wmMsgNotifyFn spec */
+    bContext *UNUSED(C),
+    wmMsgSubscribeKey *UNUSED(msg_key),
+    wmMsgSubscribeValue *msg_val)
+{
+  ScrArea *sa = msg_val->owner;
+  ED_area_tag_redraw(sa);
+}
+void ED_area_do_msg_notify_tag_refresh(
+    /* Follow wmMsgNotifyFn spec */
+    bContext *UNUSED(C),
+    wmMsgSubscribeKey *UNUSED(msg_key),
+    wmMsgSubscribeValue *msg_val)
 {
   ScrArea *sa = msg_val->user_data;
   ED_area_tag_refresh(sa);
 }
 
+void ED_area_do_mgs_subscribe_for_tool_header(
+    /* Follow ARegionType.message_subscribe */
+    const struct bContext *UNUSED(C),
+    struct WorkSpace *workspace,
+    struct Scene *UNUSED(scene),
+    struct bScreen *UNUSED(screen),
+    struct ScrArea *sa,
+    struct ARegion *UNUSED(ar),
+    struct wmMsgBus *mbus)
+{
+  /* TODO(campbell): investigate why ED_region_do_msg_notify_tag_redraw doesn't work here. */
+  wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {
+      .owner = sa,
+      .user_data = sa,
+      .notify = ED_area_do_msg_notify_tag_redraw,
+  };
+  WM_msg_subscribe_rna_prop(
+      mbus, &workspace->id, workspace, WorkSpace, tools, &msg_sub_value_region_tag_redraw);
+}
+
 /**
  * Although there's no general support for minimizing areas, the status-bar can
  * be snapped to be only a few pixels high. A few pixels rather than 0 so it
@@ -931,7 +965,7 @@ static bool region_azone_edge_poll(const ARegion *ar, const bool is_fullscreen)
   if (is_hidden && is_fullscreen) {
     return false;
   }
-  if (!is_hidden && ar->regiontype == RGN_TYPE_HEADER) {
+  if (!is_hidden && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
     return false;
   }
 
@@ -1011,6 +1045,12 @@ static void region_azones_add(const bScreen *screen, ScrArea *sa, ARegion *ar, c
 {
   const bool is_fullscreen = screen->state == SCREENFULL;
 
+  /* Only display tab or icons when the header region is hidden
+   * (not the tool header - they overlap). */
+  if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
+    return;
+  }
+
   /* edge code (t b l r) is along which area edge azone will be drawn */
   if (alignment == RGN_ALIGN_TOP)
     region_azone_edge_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
@@ -1183,6 +1223,9 @@ static void region_rect_recursive(
   else if (ar->regiontype == RGN_TYPE_HEADER) {
     prefsizey = ED_area_headersize();
   }
+  else if (ar->regiontype == RGN_TYPE_TOOL_HEADER) {
+    prefsizey = ED_area_headersize();
+  }
   else if (ar->regiontype == RGN_TYPE_FOOTER) {
     prefsizey = ED_area_footersize();
   }
@@ -1937,7 +1980,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
       /* Spaces with footer. */
       if (st->spaceid == SPACE_TEXT) {
         for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
-          if (ar->regiontype == RGN_TYPE_HEADER) {
+          if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
             ar->alignment = header_alignment;
           }
           if (ar->regiontype == RGN_TYPE_FOOTER) {
@@ -1950,7 +1993,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
       }
       else {
         for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
-          if (ar->regiontype == RGN_TYPE_HEADER) {
+          if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
             ar->alignment = header_alignment;
             break;
           }
@@ -2035,6 +2078,7 @@ static ThemeColorID region_background_color_id(const bContext *C, const ARegion
 
   switch (region->regiontype) {
     case RGN_TYPE_HEADER:
+    case RGN_TYPE_TOOL_HEADER:
       if (ED_screen_area_active(C) || ED_area_is_global(area)) {
         return TH_HEADER;
       }
index 8caa960..259076f 100644 (file)
@@ -428,6 +428,10 @@ static void screen_refresh_headersizes(void)
     if (art)
       art->prefsizey = ED_area_headersize();
 
+    art = BKE_regiontype_from_id(st, RGN_TYPE_TOOL_HEADER);
+    if (art)
+      art->prefsizey = ED_area_headersize();
+
     art = BKE_regiontype_from_id(st, RGN_TYPE_FOOTER);
     if (art)
       art->prefsizey = ED_area_headersize();
@@ -679,7 +683,7 @@ void ED_screen_set_active_region(bContext *C, wmWindow *win, const int xy[2])
 
         if (do_draw) {
           for (ar = area_iter->regionbase.first; ar; ar = ar->next) {
-            if (ar->regiontype == RGN_TYPE_HEADER) {
+            if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
               ED_region_tag_redraw_no_rebuild(ar);
             }
           }
@@ -813,16 +817,14 @@ static int screen_global_header_size(void)
 
 static void screen_global_topbar_area_refresh(wmWindow *win, bScreen *screen)
 {
-  const short size_min = screen_global_header_size();
-  const short size_max = 2.25 * screen_global_header_size();
-  const short size = (screen->flag & SCREEN_COLLAPSE_TOPBAR) ? size_min : size_max;
+  const short size = screen_global_header_size();
   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_max;
+  rect.ymin = rect.ymax - size;
 
   screen_global_area_refresh(
-      win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size_min, size_max);
+      win, screen, SPACE_TOPBAR, GLOBAL_AREA_ALIGN_TOP, &rect, size, size, size);
 }
 
 static void screen_global_statusbar_area_refresh(wmWindow *win, bScreen *screen)
@@ -845,14 +847,11 @@ void ED_screen_global_areas_sync(wmWindow *win)
    * global areas should just become part of the screen instead. */
   bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
 
-  screen->flag &= ~(SCREEN_COLLAPSE_STATUSBAR | SCREEN_COLLAPSE_TOPBAR);
+  screen->flag &= ~SCREEN_COLLAPSE_STATUSBAR;
 
   for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) {
     if (area->global->cur_fixed_height == area->global->size_min) {
-      if (area->spacetype == SPACE_TOPBAR) {
-        screen->flag |= SCREEN_COLLAPSE_TOPBAR;
-      }
-      else if (area->spacetype == SPACE_STATUSBAR) {
+      if (area->spacetype == SPACE_STATUSBAR) {
         screen->flag |= SCREEN_COLLAPSE_STATUSBAR;
       }
     }
@@ -1278,6 +1277,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const s
         if (ELEM(ar->regiontype,
                  RGN_TYPE_UI,
                  RGN_TYPE_HEADER,
+                 RGN_TYPE_TOOL_HEADER,
                  RGN_TYPE_FOOTER,
                  RGN_TYPE_TOOLS,
                  RGN_TYPE_NAV_BAR,
index 07f6055..4e39f56 100644 (file)
@@ -1324,7 +1324,7 @@ static void area_move_set_limits(
       int size_max = ED_area_global_max_size_y(area) - 1;
 
       size_min = max_ii(size_min, 0);
-      BLI_assert(size_min < size_max);
+      BLI_assert(size_min <= size_max);
 
       /* logic here is only tested for lower edge :) */
       /* left edge */
@@ -2338,12 +2338,12 @@ static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
       }
       else if (scalear->alignment == RGN_ALIGN_TOP &&
                (ar->alignment == RGN_ALIGN_BOTTOM ||
-                ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER))) {
+                ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER))) {
         dist -= ar->winy;
       }
       else if (scalear->alignment == RGN_ALIGN_BOTTOM &&
                (ar->alignment == RGN_ALIGN_TOP ||
-                ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER))) {
+                ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER))) {
         dist -= ar->winy;
       }
     }
@@ -2430,6 +2430,18 @@ static void region_scale_toggle_hidden(bContext *C, RegionMoveData *rmd)
 
   region_toggle_hidden(C, rmd->ar, 0);
   region_scale_validate_size(rmd);
+
+  if ((rmd->ar->flag & RGN_FLAG_HIDDEN) == 0) {
+    if (rmd->ar->regiontype == RGN_TYPE_HEADER) {
+      ARegion *ar_tool_header = BKE_area_find_region_type(rmd->sa, RGN_TYPE_TOOL_HEADER);
+      if (ar_tool_header != NULL) {
+        if ((ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER) == 0 &&
+            (ar_tool_header->flag & RGN_FLAG_HIDDEN) != 0) {
+          region_toggle_hidden(C, ar_tool_header, 0);
+        }
+      }
+    }
+  }
 }
 
 static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -3794,11 +3806,16 @@ void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *UN
   ARegion *ar = CTX_wm_region(C);
   const char *but_flip_str = (ar->alignment == RGN_ALIGN_TOP) ? IFACE_("Flip to Bottom") :
                                                                 IFACE_("Flip to Top");
-
-  if (!ELEM(sa->spacetype, SPACE_TOPBAR)) {
+  {
     PointerRNA ptr;
     RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, sa->spacedata.first, &ptr);
     uiItemR(layout, &ptr, "show_region_header", 0, IFACE_("Show Header"), ICON_NONE);
+    if (BKE_area_find_region_type(sa, RGN_TYPE_TOOL_HEADER)) {
+      ARegion *ar_header = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+      uiLayoutSetActive(layout, (ar_header->flag & RGN_FLAG_HIDDEN) == 0);
+      uiItemR(layout, &ptr, "show_region_tool_header", 0, IFACE_("Show Tool Settings"), ICON_NONE);
+      uiLayoutSetActive(layout, true);
+    }
   }
 
   /* default is WM_OP_INVOKE_REGION_WIN, which we don't want here. */
@@ -4058,7 +4075,7 @@ static int match_region_with_redraws(int spacetype,
     if (redraws & TIME_ALL_BUTS_WIN)
       return 1;
   }
-  else if (regiontype == RGN_TYPE_HEADER) {
+  else if (ELEM(regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER)) {
     if (spacetype == SPACE_ACTION)
       return 1;
   }
index ded19b1..1e1d1e5 100644 (file)
@@ -134,6 +134,13 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce
   scopes_new(&simage->scopes);
   simage->sample_line_hist.height = 100;
 
+  /* tool header */
+  ar = MEM_callocN(sizeof(ARegion), "tool header for image");
+
+  BLI_addtail(&simage->regionbase, ar);
+  ar->regiontype = RGN_TYPE_TOOL_HEADER;
+  ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+
   /* header */
   ar = MEM_callocN(sizeof(ARegion), "header for image");
 
@@ -1033,6 +1040,17 @@ void ED_spacetype_image(void)
   art->draw = image_tools_region_draw;
   BLI_addhead(&st->regiontypes, art);
 
+  /* regions: tool header */
+  art = MEM_callocN(sizeof(ARegionType), "spacetype image tool header region");
+  art->regionid = RGN_TYPE_TOOL_HEADER;
+  art->prefsizey = HEADERY;
+  art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
+  art->listener = image_header_region_listener;
+  art->init = image_header_region_init;
+  art->draw = image_header_region_draw;
+  art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header;
+  BLI_addhead(&st->regiontypes, art);
+
   /* regions: header */
   art = MEM_callocN(sizeof(ARegionType), "spacetype image region");
   art->regionid = RGN_TYPE_HEADER;
index 46a86bc..8b29000 100644 (file)
@@ -71,10 +71,6 @@ static SpaceLink *topbar_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sc
   ar->alignment = RGN_ALIGN_RIGHT | RGN_SPLIT_PREV;
 
   /* main regions */
-  ar = MEM_callocN(sizeof(ARegion), "right aligned main region for topbar");
-  BLI_addtail(&stopbar->regionbase, ar);
-  ar->regiontype = RGN_TYPE_WINDOW;
-  ar->alignment = RGN_ALIGN_RIGHT;
   ar = MEM_callocN(sizeof(ARegion), "main region of topbar");
   BLI_addtail(&stopbar->regionbase, ar);
   ar->regiontype = RGN_TYPE_WINDOW;
index a829584..8a0d1b5 100644 (file)
@@ -293,6 +293,13 @@ static SpaceLink *view3d_new(const ScrArea *UNUSED(sa), const Scene *scene)
   v3d->vertex_opacity = 1.0f;
   v3d->gp_flag |= V3D_GP_SHOW_EDIT_LINES;
 
+  /* tool header */
+  ar = MEM_callocN(sizeof(ARegion), "tool header for view3d");
+
+  BLI_addtail(&v3d->regionbase, ar);
+  ar->regiontype = RGN_TYPE_TOOL_HEADER;
+  ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
+
   /* header */
   ar = MEM_callocN(sizeof(ARegion), "header for view3d");
 
@@ -1120,6 +1127,34 @@ static void view3d_header_region_listener(wmWindow *UNUSED(win),
       }
       break;
   }
+
+  /* From topbar, which ones are needed? split per header? */
+  /* Disable for now, re-enable if neede, or remove - campbell. */
+#if 0
+  /* context changes */
+  switch (wmn->category) {
+    case NC_WM:
+      if (wmn->data == ND_HISTORY) {
+        ED_region_tag_redraw(ar);
+      }
+      break;
+    case NC_SCENE:
+      if (wmn->data == ND_MODE) {
+        ED_region_tag_redraw(ar);
+      }
+      break;
+    case NC_SPACE:
+      if (wmn->data == ND_SPACE_VIEW3D) {
+        ED_region_tag_redraw(ar);
+      }
+      break;
+    case NC_GPENCIL:
+      if (wmn->data == ND_DATA) {
+        ED_region_tag_redraw(ar);
+      }
+      break;
+  }
+#endif
 }
 
 static void view3d_header_region_message_subscribe(const struct bContext *UNUSED(C),
@@ -1489,6 +1524,17 @@ void ED_spacetype_view3d(void)
   art->draw = view3d_tools_region_draw;
   BLI_addhead(&st->regiontypes, art);
 
+  /* regions: tool header */
+  art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tool header region");
+  art->regionid = RGN_TYPE_TOOL_HEADER;
+  art->prefsizey = HEADERY;
+  art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
+  art->listener = view3d_header_region_listener;
+  art->init = view3d_header_region_init;
+  art->draw = view3d_header_region_draw;
+  art->message_subscribe = view3d_header_region_message_subscribe;
+  BLI_addhead(&st->regiontypes, art);
+
   /* regions: header */
   art = MEM_callocN(sizeof(ARegionType), "spacetype view3d header region");
   art->regionid = RGN_TYPE_HEADER;
@@ -1497,7 +1543,7 @@ void ED_spacetype_view3d(void)
   art->listener = view3d_header_region_listener;
   art->init = view3d_header_region_init;
   art->draw = view3d_header_region_draw;
-  art->message_subscribe = view3d_header_region_message_subscribe;
+  art->message_subscribe = ED_area_do_mgs_subscribe_for_tool_header;
   BLI_addhead(&st->regiontypes, art);
 
   /* regions: hud */
index 747c8d4..59d3076 100644 (file)
@@ -471,7 +471,7 @@ enum {
 
 /** #bScreen.flag */
 enum {
-  SCREEN_COLLAPSE_TOPBAR = 1,
+  SCREEN_DEPRECATED = 1,
   SCREEN_COLLAPSE_STATUSBAR = 2,
 };
 
@@ -589,6 +589,7 @@ enum {
   /* A place for buttons to trigger execution of something that was set up in other regions. */
   RGN_TYPE_EXECUTE = 10,
   RGN_TYPE_FOOTER = 11,
+  RGN_TYPE_TOOL_HEADER = 12,
 };
 /* use for function args */
 #define RGN_TYPE_ANY -1
index 5913376..89996cf 100644 (file)
@@ -43,6 +43,7 @@ const EnumPropertyItem rna_enum_region_type_items[] = {
     {RGN_TYPE_NAV_BAR, "NAVIGATION_BAR", 0, "Navigation Bar", ""},
     {RGN_TYPE_EXECUTE, "EXECUTE", 0, "Execute Buttons", ""},
     {RGN_TYPE_FOOTER, "FOOTER", 0, "Footer", ""},
+    {RGN_TYPE_TOOL_HEADER, "TOOL_HEADER", 0, "Tool Header", ""},
     {0, NULL, 0, NULL, NULL},
 };
 
@@ -550,11 +551,6 @@ static void rna_def_screen(BlenderRNA *brna)
   RNA_def_property_boolean_funcs(prop, "rna_Screen_fullscreen_get", NULL);
   RNA_def_property_ui_text(prop, "Maximize", "An area is maximized, filling this screen");
 
-  prop = RNA_def_property(srna, "show_topbar", PROP_BOOLEAN, PROP_NONE);
-  RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCREEN_COLLAPSE_TOPBAR);
-  RNA_def_property_ui_text(prop, "Show Top Bar", "Show top bar with tool settings");
-  RNA_def_property_update(prop, 0, "rna_Screen_bar_update");
-
   prop = RNA_def_property(srna, "show_statusbar", PROP_BOOLEAN, PROP_NONE);
   RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SCREEN_COLLAPSE_STATUSBAR);
   RNA_def_property_ui_text(prop, "Show Status Bar", "Show status bar");
index 04032d0..984536b 100644 (file)
@@ -622,12 +622,44 @@ static bool rna_Space_show_region_header_get(PointerRNA *ptr)
 static void rna_Space_show_region_header_set(PointerRNA *ptr, bool value)
 {
   rna_Space_bool_from_region_flag_set_by_type(ptr, RGN_TYPE_HEADER, RGN_FLAG_HIDDEN, !value);
+
+  /* Special case, never show the tool properties when the header is invisible. */
+  bool value_for_tool_header = value;
+  if (value == true) {
+    ScrArea *sa = rna_area_from_space(ptr);
+    ARegion *ar_tool_header = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_HEADER);
+    if (ar_tool_header != NULL) {
+      value = !(ar_tool_header->flag & RGN_FLAG_HIDDEN_BY_USER);
+    }
+  }
+  rna_Space_bool_from_region_flag_set_by_type(
+      ptr, RGN_TYPE_TOOL_HEADER, RGN_FLAG_HIDDEN, !value_for_tool_header);
 }
 static void rna_Space_show_region_header_update(bContext *C, PointerRNA *ptr)
 {
   rna_Space_bool_from_region_flag_update_by_type(C, ptr, RGN_TYPE_HEADER, RGN_FLAG_HIDDEN);
 }
 
+/* Tool Header Region.
+ *
+ * This depends on the 'RGN_TYPE_TOOL_HEADER'
+ */
+static bool rna_Space_show_region_tool_header_get(PointerRNA *ptr)
+{
+  return !rna_Space_bool_from_region_flag_get_by_type(
+      ptr, RGN_TYPE_TOOL_HEADER, RGN_FLAG_HIDDEN_BY_USER);
+}
+static void rna_Space_show_region_tool_header_set(PointerRNA *ptr, bool value)
+{
+  rna_Space_bool_from_region_flag_set_by_type(
+      ptr, RGN_TYPE_TOOL_HEADER, RGN_FLAG_HIDDEN_BY_USER, !value);
+  rna_Space_bool_from_region_flag_set_by_type(ptr, RGN_TYPE_TOOL_HEADER, RGN_FLAG_HIDDEN, !value);
+}
+static void rna_Space_show_region_tool_header_update(bContext *C, PointerRNA *ptr)
+{
+  rna_Space_bool_from_region_flag_update_by_type(C, ptr, RGN_TYPE_TOOL_HEADER, RGN_FLAG_HIDDEN);
+}
+
 /* Tools Region. */
 static bool rna_Space_show_region_toolbar_get(PointerRNA *ptr)
 {
@@ -2422,6 +2454,10 @@ static void rna_def_space_generic_show_region_toggles(StructRNA *srna, int regio
     } \
     ((void)0)
 
+  if (region_type_mask & (1 << RGN_TYPE_TOOL_HEADER)) {
+    region_type_mask &= ~(1 << RGN_TYPE_TOOL_HEADER);
+    DEF_SHOW_REGION_PROPERTY(show_region_tool_header, "Tool Header", "");
+  }
   if (region_type_mask & (1 << RGN_TYPE_HEADER)) {
     region_type_mask &= ~(1 << RGN_TYPE_HEADER);
     DEF_SHOW_REGION_PROPERTY(show_region_header, "Header", "");
@@ -3546,8 +3582,9 @@ static void rna_def_space_view3d(BlenderRNA *brna)
   RNA_def_struct_sdna(srna, "View3D");
   RNA_def_struct_ui_text(srna, "3D View Space", "3D View space data");
 
-  rna_def_space_generic_show_region_toggles(
-      srna, (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD));
+  rna_def_space_generic_show_region_toggles(srna,
+                                            ((1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_TOOLS) |
+                                             (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD)));
 
   prop = RNA_def_property(srna, "camera", PROP_POINTER, PROP_NONE);
   RNA_def_property_flag(prop, PROP_EDITABLE);
@@ -4054,7 +4091,7 @@ static void rna_def_space_image(BlenderRNA *brna)
   RNA_def_struct_ui_text(srna, "Space Image Editor", "Image and UV editor space data");
 
   rna_def_space_generic_show_region_toggles(
-      srna, (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD));
+      srna, (1 << RGN_TYPE_TOOL_HEADER) | (1 << RGN_TYPE_TOOLS) | (1 << RGN_TYPE_UI) | (1 << RGN_TYPE_HUD));
 
   /* image */
   prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
index 1cc4565..d61f9be 100644 (file)
@@ -1463,7 +1463,7 @@ static int wm_operator_invoke(bContext *C,
         /* exception, cont. grab in header is annoying */
         if (wrap) {
           ARegion *ar = CTX_wm_region(C);
-          if (ar && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_FOOTER)) {
+          if (ar && ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TOOL_HEADER, RGN_TYPE_FOOTER)) {
             wrap = false;
           }
         }
@@ -4926,7 +4926,12 @@ 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_FOOTER, RGN_TYPE_TEMPORARY, RGN_TYPE_HUD)) {
+  if (ELEM(ar->regiontype,
+           RGN_TYPE_HEADER,
+           RGN_TYPE_TOOL_HEADER,
+           RGN_TYPE_FOOTER,
+           RGN_TYPE_TEMPORARY,
+           RGN_TYPE_HUD)) {
     return;
   }
   /* Fallback to window. */