I just can't figure out how to create a custom popup which can receive data etc. What I want to do is let the user select one of the currently selected UV-layers and just hand that back to me. So I created a class like this:

class UVLayerPrompt(Operator):
    """
    Prompts the user for the uv-layer he wishes to select for each object
    """
    bl_idname = "mhmu.uvprompt"
    bl_label = "Choose the uv-layer"

    uv_layerPos = 0
    def execute(self, context):
        print('HI')
    def invoke(self, context, event):
        self.layout.template_list("UI_UL_list", #is this correct? I guess not...
            list_id="UVLayer_LIST", # I guess yes
            dataptr=context.object.data, # my guess: yes
            propname="uv_textures", # yes?
            active_dataptr=context.scene, # I could use some other location, okay
            active_propname="uv_layerPos") # I have to assign a IntegerProperty to this, right?
        return {'RUNNING_MODAL'}

after I registered my class etc.

when I call window_manager.invoke_popup(UVLayerPrompt) then it says:

TypeError: WindowManager.invoke_popup(): error with argument 1, "operator" - >Function.operator expected a Operator type, not OrderedMeta

I realized that this is not correct. Still I don't know how to react with the context (how do I popup a new instance? with python code ofc?, how do I read the chosen value from that?)

EDIT: I will try to clarify my question: I have an export script that may export several objects. For each of these objects I want to ask the user in a responsive way which uv-texture he wants to be exported. Only one layer per object should be possible and of course I have to call the popup within my script (NOT by the user) and after it run I have to know the result of it.

How far have I gotten with this by now? Using the answer below me I realized that I should use a script that is 'INTERNAL'. Secondly I think I now finally understand how Operators are supposed to work.

I figured out how to do it: if you want to call a script from inside a script you have to call bpy.ops.operator.name('INVOKE_DEFAULT')

up vote 7 down vote accepted

invoke_props_dialog(...) seems more appropriate here. It opens a popup with an OK button, and the operator's execute() method will only be called if the user clicks this button. (The other popup types execute on every property change.)

A dynamic EnumProperty is populated automatically with all UV textures of the current object (see uvtex_items callback). It is added to the dialog as expanded prop(...), remove expand=True if you want a dropdown list instead.

invoke_* require an operator instance (object), not an operator class (type). You usually pass self, which is a reference to the operator instance:

import bpy

def uvtex_items(self, context):
    return [(t.name, t.name, t.name) for t in context.object.data.uv_textures]

class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"
    bl_options = {'REGISTER', 'UNDO'}

    uvtex = bpy.props.EnumProperty(items=uvtex_items)

    @classmethod
    def poll(cls, context):
        return (context.object is not None and
                context.object.type == 'MESH' and
                len(context.object.data.uv_textures) > 0)

    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self)

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        col.prop(self, "uvtex", expand=True)

    def execute(self, context):
        self.report({'INFO'}, self.uvtex)
        return {'FINISHED'}


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


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


if __name__ == "__main__":
    register()

Paste the code into Text Editor and Run Script. Then move your mouse over 3D View, hit Spacebar, search for Simple and run the Simple Object Operator.

  • So how would I call a new popup from outside? For each object U want to have the users choice. How would I let Blender open an instance of UVLayerPrompt? – WorldSEnder Jan 25 '14 at 3:56
  • So you want to open a sequence of popups, to let the user pick a UV map, with no option to abort this process? Or let the user click some button for each object? Not sure what you mean with uvtex_items, functions are first-class citizens in python. My code requires the active object to be a mesh object with at least one UV map, or Simple Object Operator won't appear in the spacebar menu list. – CoDEmanX Jan 25 '14 at 10:18
  • I clearified the question a bit (in EDIT:) – WorldSEnder Jan 25 '14 at 15:50
  • Ah ok, yeah. Well, you need to use a different execution context for a dialog, since its modal handler is added in the invoke method, not execute (but execute is called by default if you call a bpy operator in script, thus the action is taken but without user interaction). – CoDEmanX Jan 26 '14 at 0:41
  • One could also use col.prop_search(self, 'uvtex', context.object.data, 'uv_textures') instead of col.prop(self, 'uvtex', expand=True). This way the user can search for specific names if he has many items. – WorldSEnder Jan 26 '14 at 17:41

Your Answer

 
discard

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.