Blender 2.8+, How to execute an operator in another window?

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


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

• 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 Jan 7 at 14:12
• Thanks brockman. This is what i was looking for. The Change Area.type looks interesting. Will investigate into the possibilities :) Jan 7 at 16:47
• Hm, no. Seems that i have to create a own class for every operator. Jan 7 at 16:59
• No need for a class. Select the default cube and run the script from: blender.stackexchange.com/questions/28929/… Jan 7 at 17:23
• 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 :) Jan 7 at 17:51

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

• Just wanted to add, this method has then just one tooltip though for two tools. Jan 13 at 10:17
• "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/… Jan 13 at 11:26
• Ah, that's cool. But how does this work with two buttons then? Jan 13 at 12:14
• 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 Jan 13 at 13:59
• 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 ^^ Jan 13 at 16:53

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,

• 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. Jan 10 at 18:32
• Could you provide an example please? Jan 12 at 7:26
• Sure: pasteall.org/YUho Consider adding a proper poll method. Jan 12 at 10:15
• Thanks. Pasteall is nothing permanent, so i will add it as a second answer here. Or you do. Then i will remove mine. Jan 12 at 16:47