Main Menu Item to open UV Editor

Greetings, fellow earthlings!

I am new to blender and want to dive into Python.
Have been dabbling in maxscript for a while, so I am not totally new to programming, but feel a little overwhelmed. As a little exercise I want to create a button somewhere in the info panel.
(Preferably in between “Window” and Help")

A thread on this forum (How to make floating windows/panels) and the blender templates got me jumpstarted, but my code does not work, as I do not get a menu button.
Could somebody please help me?

import bpy


class CustomMenu(bpy.types.Menu):
    bl_label = "mMenu"
    bl_idname = "OBJECT_MT_mMenu"
    
    def openuveditor():
        obj_original_area = bpy.context.area
        obj_original_type = obj_original_area.type

        obj_original_area.type = 'IMAGE_EDITOR'
        bpy.ops.screen.area_dupli('INVOKE_DEFAULT')

        obj_original_area.type = obj_original_type
        

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

        layout.operator("openuveditor()")



def draw_item(self, context):
    layout = self.layout
    layout.menu(CustomMenu.bl_idname)


def register():
    bpy.utils.register_class(CustomMenu)
    bpy.types.INFO_HT_header.append(draw_item)


def unregister():
    bpy.utils.unregister_class(CustomMenu)
    bpy.types.INFO_HT_header.remove(draw_item)

if __name__ == "__main__":
    register()

Oookay, so after a few hours of more tutorials (I can recommend this series: https://www.youtube.com/watch?v=K0yb4sZ7B4g), I think I understand more.
The workflow would be to first create an operator which I can then load through a button, right?
So I am trying to register that class, but it throws an error message:

Traceback (most recent call last):
File “<blender_console>”, line 1, in
File “C:\Program Files\Blender Foundation\blender-2.80.0-git.0e8bd6ba8a2-windows64\2.80\scripts\modules\bpy\ops.py”, line 192, in call
ret = op_call(self.idname_py(), None, kw)
RuntimeError: Operator bpy.ops.mops.openuveditor.poll() failed, context is incorrect

I believe the “context” behind the main definition (how would you call that parameter, is it an argument?) is the wrong part, however I am unsure what else to put there…

Here is my code for now, derived from the threadI linked earlier and the “simple operator” template:

import bpy


def main(contex):
    bl_idname = "mops.openuveditor"
    bl_label = "UV Editor"
    obj_original_area = bpy.context.area
    obj_original_type = obj_original_area.type

    obj_original_area.type = 'IMAGE_EDITOR'
    bpy.ops.screen.area_dupli('INVOKE_DEFAULT')

    obj_original_area.type = obj_original_type


class OpenUVEditor(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "mops.openuveditor"
    bl_label = "Open UV Editor"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        main(contex)
        return {'FINISHED'}


def register():
    bpy.utils.register_class(OpenUVEditor)


def unregister():
    bpy.utils.unregister_class(OpenUVEditor)


if __name__ == "__main__":
    register()

    # test call
    #bpy.ops.mops.openuveditor()

Maybe somebody wants to tell me what an idiot I am for doing everything wrong? I can take it! :slight_smile:
(As long as you tell me how to do it right, too, that is…)

Okay, got it to work… mostly… still trying to change the new window’s size and position and save them in global variables.
Ideally i would also like to load the diffuse image of the selected object in the background automatically, if it has any.
Should I keep posting? For anybody who’s interested, here is the working code:

bl_info = {
    "name": "mMenu",
    "author": "morph3us",
    "version": (0, 1),
    "blender": (2, 79, 0),
    "location": "Info Menu",
    "description": "Adds a new menu in the info toolbar",
    "warning": "",
    "wiki_url": "",
    "category": "Menu",
    }

import bpy


def fn_openuvedit():
    bl_idname = "mops_openuveditor"
    bl_label = "UV Editor"
    obj_original_area = bpy.context.area
    obj_original_type = obj_original_area.type
    obj_original_area.type = 'IMAGE_EDITOR'
    bpy.ops.screen.area_dupli('INVOKE_DEFAULT')
    obj_original_area.type = obj_original_type


class op_openuvedit(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.op_openuvedit"
    bl_label = "Open UV Editor Window"


    def execute(self, context):
        fn_openuvedit()
        return {'FINISHED'}
        

class obj_mmenu(bpy.types.Menu):
    bl_label = "mMenu"
    bl_idname = "OBJECT_MT_mMenu"
    
    def draw(self, context):
        layout = self.layout

        layout.operator("object.op_openuvedit")



def draw_item(self, context):
    layout = self.layout
    layout.menu(obj_mmenu.bl_idname)


def register():
    bpy.utils.register_class(op_openuvedit)
    bpy.utils.register_class(obj_mmenu)
    bpy.types.INFO_HT_header.append(draw_item)


def unregister():
    bpy.utils.unregister_class(op_openuvedit)
    bpy.utils.unregister_class(obj_mmenu)
    bpy.types.INFO_HT_header.remove(draw_item)

if __name__ == "__main__":
    register()

Hey good Job. I try to do the same but with 2.8
I edited the startup script to get the results I want but it is not a nice solution. I would love to call a script trough blender to add the menu after the launch as you did. So if you are able to convert your code to 2.8 I would be more than happy to know how