Register Panel#

This document describes the panel registration system in the UVFlow addon_utils module, which provides multiple ways to create and register UI panels for different Blender editors.

Overview#

The panel registration system supports:

  1. Multiple editor types (3D Viewport, Image Editor, etc.)

  2. Automatic ID and label generation from class names

  3. Custom tabs and categories for organization

  4. Popover panels for compact UI

  5. Integration with existing panels via append

Basic Panel Types#

3D Viewport Panel#

Create panels in the 3D Viewport sidebar:

from ..addon_utils import Register
from bpy.types import Context, UILayout

@Register.UI.PANEL.VIEW3D
class TestPanel:
    label = 'UVFlow Toolset'
    tab = 'UVFlow'  # Custom tab name (optional)
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        layout.label(text="Hey!", icon='DOT')
        layout.operator("mesh.primitive_cube_add", text="Add Cube")
        
        # Conditional content
        if context.active_object:
            layout.prop(context.active_object, "name")

Image Editor Panel#

Create panels in the Image Editor sidebar:

@Register.UI.PANEL.IMAGE_EDITOR
class ImageToolsPanel:
    label = 'Image Tools'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        layout.label(text="Image Editor Tools")
        if context.edit_image:
            layout.prop(context.edit_image, "name")

Custom Panel Location#

Create panels in specific editor locations:

@Register.UI.PANEL.new('PROPERTIES', 'WINDOW', bl_context='material')
class MaterialPanel:
    label = 'Custom Material Panel'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        layout.label(text="Custom material tools")

Popover Panels#

Basic Popover#

Create compact popover panels:

@Register.UI.POPOVER
class TestPopoverPanel:
    label = 'Settings'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        layout.label(text="Hello there!", icon='MONKEY')
        
        col = layout.column()
        col.prop(context.scene, "frame_start")
        col.prop(context.scene, "frame_end")

Popover Integration#

Add popovers to existing UI:

@Register.UI.APPEND(bpy.types.DATA_PT_uv_texture, prepend=False)
def draw_append_popover_panel(context: Context, layout: UILayout) -> None:
    TestPopoverPanel.draw_in_layout(layout, text="Settings", icon='SETTINGS')

Panel Organization#

Custom Tabs#

@Register.UI.PANEL.VIEW3D
class OrganizedPanel:
    label = 'My Tools'
    tab = 'MyAddon'  # Creates/uses custom tab
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        layout.label(text="Organized in custom tab")

Common UI Patterns#

Property Groups#

@Register.UI.PANEL.VIEW3D
class PropertiesPanel:
    label = 'Settings'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        scene = context.scene
        
        # Group related properties
        box = layout.box()
        box.label(text="Export Settings:")
        box.prop(scene, "export_scale")
        box.prop(scene, "export_format")
        
        # Another group
        box = layout.box()
        box.label(text="Display Settings:")
        box.prop(scene, "show_wireframe")
        box.prop(scene, "show_overlays")

Operator Integration#

@Register.UI.PANEL.VIEW3D
class OperatorPanel:
    label = 'Actions'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        # Simple operator buttons
        layout.operator("uvflow.unwrap", text="Unwrap UVs")
        layout.operator("uvflow.pack", text="Pack UVs")
        
        # Operator with custom properties
        op = layout.operator("uvflow.export", text="Export")
        op.format = 'OBJ'
        op.scale = 2.0
        
        # Operator in a row
        row = layout.row()
        row.operator("uvflow.select_all")
        row.operator("uvflow.deselect_all")

Dynamic Content#

@Register.UI.PANEL.VIEW3D
class DynamicPanel:
    label = 'Dynamic Content'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        obj = context.active_object
        
        if not obj:
            layout.label(text="No active object", icon='ERROR')
            return
        
        layout.label(text=f"Object: {obj.name}")
        
        if obj.type == 'MESH':
            mesh = obj.data
            layout.label(text=f"Vertices: {len(mesh.vertices)}")
            layout.label(text=f"Faces: {len(mesh.polygons)}")
        elif obj.type == 'CURVE':
            layout.label(text="Curve object")
            layout.prop(obj.data, "resolution_u")

Best Practices#

1. Use Descriptive Labels#

# Good
@Register.UI.PANEL.VIEW3D
class UVUnwrapToolsPanel:
    label = 'UV Unwrap Tools'

# Avoid
@Register.UI.PANEL.VIEW3D
class Panel1:
    label = 'Panel'

2. Implement Proper Polling#

@Register.UI.PANEL.VIEW3D
class MeshOnlyPanel:
    label = 'Mesh Tools'
    
    @classmethod
    def poll(cls, context):
        return (context.active_object and 
                context.active_object.type == 'MESH')

3. Organize UI Logically#

@Register.UI.PANEL.VIEW3D
class WellOrganizedPanel:
    label = 'Tools'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        # Group related functionality
        col = layout.column(align=True)
        col.label(text="Selection:")
        col.operator("mesh.select_all")
        col.operator("mesh.select_random")
        
        layout.separator()
        
        col = layout.column(align=True)
        col.label(text="Modification:")
        col.operator("mesh.subdivide")
        col.operator("mesh.inset_faces")

4. Handle Missing Data Gracefully#

@Register.UI.PANEL.VIEW3D
class RobustPanel:
    label = 'Robust Panel'
    
    def draw_ui(self, context: Context, layout: UILayout) -> None:
        try:
            obj = context.active_object
            if obj and obj.data:
                layout.prop(obj.data, "name")
            else:
                layout.label(text="No data available")
        except AttributeError:
            layout.label(text="Error accessing data", icon='ERROR')

This panel registration system provides a flexible foundation for creating organized, functional UI panels across different Blender editors with minimal boilerplate code.