1
$\begingroup$

Is there any way to control the starting position of a popup panel / window?

I'm not familiar with the number of floating panel types in Blender, but I'm creating mine with an operator class, using bpy.context.window_manager.invoke_props_dialog(self,width=600) in invoke().

The default starting popup location seems to be related to the mouse cursor or activator button location. The problem occurs when the button to open the popup is near the bottom of the screen. The popup opens into the bottom right corner. I don't need to specify the exact location. But if possible, I would like to have it open somewhere near the vertical center of my standard side panel.

$\endgroup$
4
  • $\begingroup$ You can set the cursor position using bpy.context.window.cursor_warp(x, y). $\endgroup$
    – Robert Gützkow
    Sep 30 '19 at 13:50
  • $\begingroup$ Would that work? I would be hesitant to move the user's cursor just to set the window position, but it may work to move it temporarily, then move it back. I will give it a try and see if it works. Thanks! $\endgroup$
    – Robert
    Sep 30 '19 at 21:19
  • $\begingroup$ That is a downside, because it's unexpected for the user. $\endgroup$
    – Robert Gützkow
    Sep 30 '19 at 21:51
  • $\begingroup$ My code is in a mess at the moment, so I can't easily test it. But my hope is that it won't be detectable by the user if I only move the cursor for the single frame. Move the cursor, possibly update something, spawn the window, move it back. It's a bit hacky, but if it works well enough, I could provide an option to "center pop ups". $\endgroup$
    – Robert
    Sep 30 '19 at 22:13
2
$\begingroup$

Hello from the future,

If we have us some properties on our operator, like so:

from bpy.types import Operator;
from bpy.props import IntProperty;

class MYADDON_OT_my_operator(Operator):

    bl_idname = "myaddon.myoperator";
    bl_label = "Pop!";
    bl_description = "Spawns a pop-up";

    # using annotations for 2.8+
    # change to equal signs on previous versions
    first_mouse_x : IntProperty(default = 0);
    first_mouse_y : IntProperty(default = 0);

    target_mouse_x : IntProperty(default = 0);
    target_mouse_y : IntProperty(default = 0);

    mouse_snap : BoolProperty(default = False);

Then we can save the original position of the mouse during invoke.

    def invoke(self, context, event):

        # assign position of the cursor at the time the operator is called
        self.first_mouse_x = event.mouse_x;
        self.first_mouse_y = event.mouse_y;

        # probably redundant but i can't recall if props actually reset to default
        self.mouse_snap = False;

        # now warp the mouse to some xy coords
        # here i center on the window and adjust y to approx. the height of my popup
        context.window.cursor_warp(context.window.width/2, (context.window.height/2) + 60);

        # now invoke
        wm = context.window_manager; 
        return wm.invoke_props_dialog(self, width = 600);

Next thing on the list is resetting the cursor to the original coordinates. I do this on the first run of draw and haven't really noticed any jumpy motion on the cursor.

    def draw(self, context):

        if not self.mouse_snap:
            self.mouse_snap = True;
            context.window.cursor_warp(self.first_mouse_x, self.first_mouse_y);

That gets you back where you started.

But wait, there's more! As a bonus, you can also pass the xy coords to the operator from your panel's draw.

    def draw(self, context):

        layout = self.layout;
        row = layout.row();

        # this gets you a handle to the operator properties
        props = row.operator("myaddon.myoperator");

        # now just assign them values as you would
        props.target_mouse_x = some_x_coord;
        props.target_mouse_y = some_y_coord;

It's a barebones example, but hopefully a good starting point for anyone else that google-wanders in here like I did. ;)

$\endgroup$
2
  • 1
    $\begingroup$ A couple of things from the present :)_ Operator properties are now (2.8+) defined using annotations eg prop_name : bpy.props.IntProperty ... and in as much as aligning with equals sign is "pretty" its not PEP8 compliant. $\endgroup$
    – batFINGER
    Jan 29 at 7:02
  • $\begingroup$ oh hi, batman! c: I'm stuck on 2.79 so the new ways slip my mind at times haha. maybe comment out the old version and add in the 2.8+ way? eh, i'll edit it later if no one does. i don't care for style guides one way or another, i go for what i find more readable, but if it's that important i'll make it ugly as well :B $\endgroup$
    – Liebranca
    Jan 30 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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