How to create "overlay buttons" like in the 3D viewport with Python?

How are these buttons called?

Is it possible to create them with Python? If yes, how?

Thanks.

Capture

Those buttons are defined in the source code, but you can create these with Python using the new GPU module. This video gives you an overview of how to create them and also provides you with a repository you can use to see the examples.

I hope this helps.

3 Likes

Is the new GPU module official from Blender? Or is it Jayanam that invented his own custom widgets?
Because I’d like to have the official buttons if possible…

Also, where can I find the API of this new GPU module for 2.8?

I will study this video in more details a little bit later. It’s always good to understand how UI works.

https://docs.blender.org/api/blender2.8/gpu.html
You can find a lot of stuff here:

1 Like

@anon18120698
Thanks that’s what I needed.

In fact, those buttons are defined using the new gizmo system. I think it’s already possible to create such gizmos from python, although the process is not documented well yet. Have a look at the gizmo templates in the script editor. The predefined gizmo type you’re looking for is called GIZMO_GT_button_2d.

2 Likes

That would be very nice. Thanks, I’ll have a look at it!

@julianeisel
I tried, but I don’t really understand the process to make this button appear on the screen UI instead of a gizmo on the object in the 3D space. When I replace
mpr = self.gizmos.new("GIZMO_GT_dial_3d") with mpr = self.gizmos.new("GIZMO_GT_button_2d"), Blender crashes.

And, unfortunately, it’s not possible to right click these “overlay buttons” to see their source code directly.

Could I ask you to write for me the lines of code to make the button appear in the lower right corner of the screen (with whatever operator) so I get the idea?

Here I am so far:

class Camera_Movements_UI_Buttons(GizmoGroup):
    bl_idname = "Camera_Movements_UI_Buttons"
    bl_label = "Camera Movements UI Buttons"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'WINDOW'
    bl_options = {'3D', 'PERSISTENT'}

    @classmethod
    def poll(cls, context):
        ob = context.object
        return (ob and ob.type == 'CAMERA')

    def setup(self, context):
        mpr = self.gizmos.new("GIZMO_GT_button_2d")   # This line crashes Blender

PS: To be more precise, I’m trying to make an addon for my proposal here:

The code crashes since it tries to draw geometry that is not defined. If you set the icon it tries to draw that instead. So you have to set the mpr.icon property.

Here’s your code modified to do what you asked for:

import bpy
from bpy.types import (
    GizmoGroup,
)

class Camera_Movements_UI_Buttons(GizmoGroup):
    bl_idname = "Camera_Movements_UI_Buttons"
    bl_label = "Camera Movements UI Buttons"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'WINDOW'
    bl_options = {'PERSISTENT', 'SCALE'}

    @classmethod
    def poll(cls, context):
        ob = context.object
        return (ob and ob.type == 'CAMERA')

    def draw_prepare(self, context):
        region = context.region

        self.foo_gizmo.matrix_basis[0][3] = region.width - 40
        self.foo_gizmo.matrix_basis[1][3] = 40

    def setup(self, context):
        mpr = self.gizmos.new("GIZMO_GT_button_2d")   # This line crashes Blender
        mpr.icon = 'OUTLINER_OB_CAMERA'
        mpr.draw_options = {'BACKDROP', 'OUTLINE'}

        mpr.alpha = 0.0
        mpr.color_highlight = 0.8, 0.8, 0.8
        mpr.alpha_highlight = 0.2

        mpr.scale_basis = (80 * 0.35) / 2 # Same as buttons defined in C
        self.foo_gizmo = mpr


bpy.utils.register_class(Camera_Movements_UI_Buttons)
2 Likes

@julianeisel
Thank you very much, I appreciate you taking the time to write this code.

Another few questions…

1 ) What does the variable mpr stand for?

2 ) How do you pass instructions to a button?

I tried adding this function inside the Camera_Movements_UI_Buttons class, but it’s not working:

def execute(self, context):
    bpy.ops.transform.translate(value=(1, 0, 0)) # Instruction example

3 ) How do you interact with the button itself:

  • by tweaking (like Move the View)?
  • by toggling (like Switch Perspective/Orthographic)?

In the API, I found these Gizmo Group Operators:
bpy.ops.gizmogroup.gizmo_select(extend=False, deselect=False, toggle=False)
bpy.ops.gizmogroup.gizmo_tweak()
Is this it? If yes, where should they be placed?

@julianeisel
I found my responses to question 2) and 3). I passed the instructions with this line:
props = mpr.target_set_operator("transform.rotate")

But there is a problem I get: when I select the camera, the buttons I wanted appear as expected but it overrides the Move gizmo which only shows for half a second then disappears. In contrast, when I select the cube the Gizmo stays.
Do you have an idea why?

I can confirm that issue here. Looks like a bug.
From what I can tell it happens when tool-system gizmos and custom gizmos are both visible.
Investigating…

Thanks. Please let me know if you find something.

Opened a report to get feedback from other devs: https://developer.blender.org/T60289

Nice, I’ll follow it.

Hello @julianeisel,

I’m trying to put custom icons to a gizmo button (as 32x32 pixels .png files located in the addon’s folder).
It’s working when I put it anywhere else in the UI, but it crashes Blender when I put it in the GIZMO_GT_button_2d:

mpr.icon = icon_free.icon_id # Blender crashes

Could you tell me what is the correct way to do it, if that’s possible?

class CameraGizmos(bpy.types.GizmoGroup):
    bl_idname = "CameraGizmos"
    bl_label = "Camera Utilities"
    bl_space_type = "VIEW_3D"
    bl_region_type = "WINDOW"
    bl_options = {'PERSISTENT', 'SCALE'}
    
    @classmethod
    def poll(cls, context):
        ob = context.object
        return (ob and ob.type=='CAMERA')
    
    def draw_prepare(self, context):
        r_xpos = context.region.width / 2 -160
        for gizmo in self.gizmos:
            gizmo.matrix_basis[0][3] = r_xpos
            gizmo.matrix_basis[1][3] = 40
            r_xpos += 55
    
    def draw(self, context): # <------------------ Is it correct to place this 'draw' function in this class?
        
        pcoll = preview_collections["main"]
        icon_free = pcoll["icon_free"] # <-------- The icon I wish to implement
    
    def setup(self, context):
        
        mpr = self.gizmos.new("GIZMO_GT_button_2d")
        mpr.icon = 'ORIENTATION_VIEW' # <--------- How to change this icon to the one above?
        mpr.draw_options = {'BACKDROP', 'OUTLINE'}
        props = mpr.target_set_operator("cameras.callop")
        props.command='TranslateXY'
        mpr.alpha = 1.0
        mpr.color = 0.1, 0.1, 0.1
        mpr.color_highlight = 0.8, 0.8, 0.8
        mpr.alpha_highlight = 0.2
        mpr.scale_basis = (80 * 0.35) / 2