0
$\begingroup$

Some operators are global. Some are not. Transform for example is bound to the window where it gets executed in. As an example let's say i want to perform the transform.rotate from the UV Editor in the UV menu of the 3D view?

All I found so far was some advice in the manual regarding execution context. This example maximizes the screen in all open 3D Views, from: https://docs.blender.org/api/current/bpy.ops.html

# maximize 3d view in all windows
import bpy

for window in bpy.context.window_manager.windows:
    screen = window.screen

    for area in screen.areas:
        if area.type == 'VIEW_3D':
            override = {'window': window, 'screen': screen, 'area': area}
            bpy.ops.screen.screen_full_area(override)
            break

But how would transform.translate fit in here? I'd like to get a button in 3D View .

To make it a bit more complicated, I don't only want to transform actually, I'd like to add back the old transform by 90 degrees back into its location. Which was:

layout.operator("transform.rotate", text="Rotate Minus 90").value = math.pi / -2

enter image description here

Do I still would have to write my own operator here? Or is there an easier way meanwhile?

$\endgroup$
7
  • $\begingroup$ You can also change the area temporarily: blender.stackexchange.com/questions/6101/… or just rotate using low-level functions: blender.stackexchange.com/a/28931/31447 and blender.stackexchange.com/a/111307/31447 $\endgroup$
    – brockmann
    Commented Jan 7, 2021 at 14:12
  • 1
    $\begingroup$ Thanks brockman. This is what i was looking for. The Change Area.type looks interesting. Will investigate into the possibilities :) $\endgroup$
    – Tiles
    Commented Jan 7, 2021 at 16:47
  • $\begingroup$ Hm, no. Seems that i have to create a own class for every operator. $\endgroup$
    – Tiles
    Commented Jan 7, 2021 at 16:59
  • $\begingroup$ No need for a class. Select the default cube and run the script from: blender.stackexchange.com/questions/28929/… $\endgroup$
    – brockmann
    Commented Jan 7, 2021 at 17:23
  • $\begingroup$ The rotate was just an example. There is much more. It's around half of the operators that needs to run in correct area when i remember right. But thanks for the hint :) $\endgroup$
    – Tiles
    Commented Jan 7, 2021 at 17:51

2 Answers 2

2
$\begingroup$

The method from brockman. It shows one of the operator buttons. For the other direction simply use bpy.ops.object.simple_operator(val=math.pi/-2)

import bpy
import math
​
class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    bl_options = {'REGISTER', 'UNDO'}
    
    val: bpy.props.FloatProperty()
    
    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    @classmethod
    def description(cls, context, properties):
        return properties.arg
​
    def execute(self, context):
        for area in bpy.context.screen.areas:
            if area.type == 'IMAGE_EDITOR':
                override = bpy.context.copy()
                override['area'] = area
                bpy.ops.transform.rotate(override, value = self.val)
        return {'FINISHED'}
​
​
def register():
    bpy.utils.register_class(SimpleOperator)
​
​
def unregister():
    bpy.utils.unregister_class(SimpleOperator)
​
​
if __name__ == "__main__":
    register()
​
    # test call
    bpy.ops.object.simple_operator(val=math.pi/2)

Buttons:

    #buttons with separated tooltips. Put it in a menu or a panel
    myvar = layout.operator(SimpleOperator.bl_idname, text="Rotate Counter Clockwise").arg = 'Tooltip for Rotate Counter Clockwise'
    myvar.val=math.pi/2

    myvar = layout.operator(SimpleOperator.bl_idname, text="Rotate Clockwise").arg = 'Tooltip for Rotate Clockwise'
    myvar.val=math.pi/-2
$\endgroup$
11
  • $\begingroup$ Just wanted to add, this method has then just one tooltip though for two tools. $\endgroup$
    – Tiles
    Commented Jan 13, 2021 at 10:17
  • $\begingroup$ "Operators can now have a dynamic tooltip that changes based on the context and operator parameters." -> wiki.blender.org/wiki/Reference/Release_Notes/2.81/… $\endgroup$
    – brockmann
    Commented Jan 13, 2021 at 11:26
  • $\begingroup$ Ah, that's cool. But how does this work with two buttons then? $\endgroup$
    – Tiles
    Commented Jan 13, 2021 at 12:14
  • 1
    $\begingroup$ As stated in the release notes: op = layout.operator(SimpleOperator.bl_idname).arg = 'FOO' \ op.val=math.pi/2, see: blender.stackexchange.com/a/2516/31447 $\endgroup$
    – brockmann
    Commented Jan 13, 2021 at 13:59
  • $\begingroup$ Thanks. I don't mean how you pass the argument, but how you distinguish the two operator cases. Sorry if i nag you too much ^^ $\endgroup$
    – Tiles
    Commented Jan 13, 2021 at 16:53
0
$\begingroup$

To have an aswer here for peopel that searches for a solution, I ended in writing my own class. When somebody has a more elegant solution, everything is welcome :)

The classes:

class TOOLBAR_MT_image_uv_rotate_clockwise(bpy.types.Operator):
    """Rotate selected UV geometry clockwise by 90 degrees"""
    bl_idname = "image.uv_rotate_clockwise"
    bl_label = "Rotate UV by 90"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        for area in bpy.context.screen.areas:
            if area.type == 'IMAGE_EDITOR':
                override = bpy.context.copy()
                override['area'] = area
                bpy.ops.transform.rotate(override, value = math.pi/-2 )
        return {'FINISHED'}

    
class TOOLBAR_MT_image_uv_rotate_counterclockwise(bpy.types.Operator):
    """Rotate selected UV geometry counter clockwise by 90 degrees"""
    bl_idname = "image.uv_rotate_counterclockwise"
    bl_label = "Rotate UV by minus 90"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        for area in bpy.context.screen.areas:
            if area.type == 'IMAGE_EDITOR':
                override = bpy.context.copy()
                override['area'] = area
                bpy.ops.transform.rotate(override, value = math.pi/2 )
        return {'FINISHED'}

The operators:

layout.operator("image.uv_rotate_clockwise", text="Rotate clockwise")
layout.operator("image.uv_rotate_counterclockwise", text="Rotate counter clockwise")

The register part:

TOOLBAR_MT_image_uv_rotate_clockwise,
TOOLBAR_MT_image_uv_rotate_counterclockwise,
$\endgroup$
4
  • $\begingroup$ The "more elegant" solution would be adding an operator float property for the rotation, which allows to pass your rotation value, that way you can also get rid of the second class. $\endgroup$
    – brockmann
    Commented Jan 10, 2021 at 18:32
  • $\begingroup$ Could you provide an example please? $\endgroup$
    – Tiles
    Commented Jan 12, 2021 at 7:26
  • 1
    $\begingroup$ Sure: pasteall.org/YUho Consider adding a proper poll method. $\endgroup$
    – brockmann
    Commented Jan 12, 2021 at 10:15
  • $\begingroup$ Thanks. Pasteall is nothing permanent, so i will add it as a second answer here. Or you do. Then i will remove mine. $\endgroup$
    – Tiles
    Commented Jan 12, 2021 at 16:47

You must log in to answer this question.

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