2
$\begingroup$

Is it possible to do this within a bpy API - a set of boolean properties where multiple can be selected, with their own icons, right next to each other like below (from the outliner filter):

Row of adjacent toggles with individual icons

Whenever I try row(align=True) or grid_flow(align=True) with multiple boolean properties, there's still a padding/margin between them:

multiple boolean properties with space between them

Is there a way to do this with individual booleans or boolean vector properties?

Here's a sample of the code (the variables are BoolProperty type):

def draw(self, context):
    layout = self.layout
    scene = context.scene

    layout.use_property_split = True

    row = layout.row(align=True)
    row.prop(scene, 'v_name',
             icon='RESTRICT_SELECT_OFF', icon_only=True)
    row.prop(scene, 'v_name2',
             icon='HIDE_OFF', icon_only=True)
$\endgroup$

2 Answers 2

4
$\begingroup$

Just pass align=True when calling the encapsulating layout element like UILayout.row(align=True), UILayout.column(align=True), or UILayout.grid_flow(align=True) to get rid of the padding:

    ...
    layout = self.layout
    row = layout.row(align=True)
    row.prop(mytool, "my_bool", icon='CAMERA_DATA', text="")
    row.prop(mytool, "my_bool", icon='CONSOLE', text="")
    row.prop(mytool, "my_bool", icon='ARMATURE_DATA', text="")
    ...

Demo based on the template from How to create a custom UI?

bl_info = {
    "name": "Add-on Template",
    "author": "p2or, brockmann",
    "version": (0, 0, 3),
    "blender": (2, 80, 0),
    "location": "3D View > Tools",
    "category": "Development"
}


import bpy

from bpy.props import BoolProperty, PointerProperty
from bpy.types import Panel, PropertyGroup

# ------------------------------------------------------------------------
#    Scene Properties
# ------------------------------------------------------------------------

class MyProperties(PropertyGroup):

    my_bool: BoolProperty(
        name="Enable or Disable",
        description="A bool property",
        default = False
        )

# ------------------------------------------------------------------------
#    Panel in Object Mode
# ------------------------------------------------------------------------

class OBJECT_PT_CustomPanel(Panel):
    bl_label = "My Panel"
    bl_idname = "OBJECT_PT_custom_panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "UI"
    bl_category = "Tools"
    bl_context = "objectmode"   


    @classmethod
    def poll(self,context):
        return context.object is not None

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool
        
        # layout.use_property_split = True
        # layout.use_property_decorate = False

        row = layout.row(align=True)
        row.prop(mytool, "my_bool", icon='CAMERA_DATA', text="")
        row.prop(mytool, "my_bool", icon='CONSOLE', text="")
        row.prop(mytool, "my_bool", icon='ARMATURE_DATA', text="")
        row.prop(mytool, "my_bool", icon='OUTLINER_OB_LIGHT', text="")
        row.prop(mytool, "my_bool", icon='BOLD', text="")
        
        grid = layout.grid_flow(columns=5, align=True)
        grid.prop(mytool, "my_bool", icon='CAMERA_DATA', text="")
        grid.prop(mytool, "my_bool", icon='CONSOLE', text="")
        grid.prop(mytool, "my_bool", icon='ARMATURE_DATA', text="")
        grid.prop(mytool, "my_bool", icon='BOLD', text="")
        
        col = layout.column(align=True)
        col.prop(mytool, "my_bool", icon='CAMERA_DATA', text="")
        col.prop(mytool, "my_bool", icon='CONSOLE', text="")
        col.prop(mytool, "my_bool", icon='ARMATURE_DATA', text="")
        col.prop(mytool, "my_bool", icon='OUTLINER_OB_LIGHT', text="")
        col.prop(mytool, "my_bool", icon='BOLD', text="")
        
# ------------------------------------------------------------------------
#    Registration
# ------------------------------------------------------------------------

classes = (
    MyProperties,
    OBJECT_PT_CustomPanel
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)

    bpy.types.Scene.my_tool = PointerProperty(type=MyProperties)

def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    del bpy.types.Scene.my_tool


if __name__ == "__main__":
    register()

Note: If you'd like to use UILayout.use_property_split, make sure you set layout.use_property_decorate to False, otherwise the panel will look like:

$\endgroup$
1
  • $\begingroup$ I had "align=True" in my case. Updated post with code sample. $\endgroup$ Commented Sep 27, 2021 at 15:18
1
$\begingroup$

Although align=True is usually the issue, I figured out it was UILayout.use_property_split in this case. I set it to "False" for the row itself and it worked as expected.

Edit: UILayout.use_property_decorate specifically adds the space for the keyframe button - I explicitly prevented these props from being animateable, so the decoration didn't show up. But the space was still made. So disabling this property also works.

$\endgroup$
5
  • 2
    $\begingroup$ You can also enable UILayout.use_property_split but disable UILayout.use_property_decorate. If I set use_property_split to true (in code above) I get these dots in between the elements: i.sstatic.net/ZyDKD.png (I think the screenshot in your question would look way different... Doesn't it?). Glad you have found the bug - however, impossible to guess based on your question IMHO. $\endgroup$
    – brockmann
    Commented Sep 27, 2021 at 15:33
  • $\begingroup$ @brockmann thank you for that - that also works. I had set my props to not be animateable, but it spaces them anyway even if they aren't visually decorated. I'll add that as well. $\endgroup$ Commented Sep 27, 2021 at 15:44
  • 1
    $\begingroup$ No problem. Can not confirm, no spaces here, looks like the same as without split enabled. Added as option to the demo so you can test it. $\endgroup$
    – brockmann
    Commented Sep 27, 2021 at 15:48
  • 2
    $\begingroup$ IMO since the default is False docs.blender.org/api/current/… the issue was that you set it to True, making question a bit like "There's something wrong with my dog, ... trick question it's a cat" Please always add all relevant code to questions in future. $\endgroup$
    – batFINGER
    Commented Sep 27, 2021 at 15:52
  • 2
    $\begingroup$ @batFINGER will do. I know that's my bad in not sharing enough information :/ $\endgroup$ Commented Sep 27, 2021 at 16:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .