2
$\begingroup$

I'd like to display a popup, that shows some custom properties. Which properties are drawn or enabled depends on the settings of some other properties of this popup. The popup is invoked by context.window_manager.invoke_props_dialog().

Here's a small example (properties are coming from the addon-preferences):

box = layout.box()
if not( up and up.preferences.simplify_ui):
    box.prop(up.preferences, "simplify_ui")

if up and up.preferences.simplify_ui:
    row = box.row()
    row.prop(prefs, "simplify_ui")

    row.prop(prefs, "auto_simplify_ui")

    #...

How can I update the popup? Thanks.

$\endgroup$
7
$\begingroup$

While your Operator.check(...) method returns True the popup will redraw.

Simple return True method used in bpy.types.Operator Dialog Box example. Setting the boolean prop, my_bool, to True reveals more in draw method.

import bpy


class DialogOperator(bpy.types.Operator):
    bl_idname = "object.dialog_operator"
    bl_label = "Simple Dialog Operator"

    my_float = bpy.props.FloatProperty(name="Some Floating Point")
    my_bool = bpy.props.BoolProperty(name="Toggle Option")
    my_string = bpy.props.StringProperty(name="String Value")

    def execute(self, context):
        message = "Popup Values: %f, %d, '%s'" % \
            (self.my_float, self.my_bool, self.my_string)
        self.report({'INFO'}, message)
        return {'FINISHED'}

    def check(self, context):
        return True

    def draw(self, context):
        layout = self.layout
        layout.prop(self, "my_bool")
        if self.my_bool:
            layout.label("It's TRUE")
            layout.prop(self, "my_string")

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


bpy.utils.register_class(DialogOperator)

# test call
bpy.ops.object.dialog_operator('INVOKE_DEFAULT')
| improve this answer | |
$\endgroup$
  • $\begingroup$ I've tested the example. It might work in other versions of blender, but in my version (version 2.76b from the Ubuntu repositories) it doesn't. I've added two print-calls at the beginning of check() and draw(). It results in this output: draw \n check \n check \n check \n .... So the draw-function is called once at the invocation but not after a change. The check-function is called every time. $\endgroup$ – thz Feb 12 '17 at 22:37
  • $\begingroup$ Don't have 2.76b to check against. On 2.78 (ubuntu) I get "draw" (when invoked) then "check draw" each time the my_bool property is (un)checked. Why not upgrade to a later version of blender. (ie don't rely on the very very slooooooooow to upgrade ubuntu repos) $\endgroup$ – batFINGER Feb 14 '17 at 15:12
  • $\begingroup$ I'm writing an addon in context of my master-thesis. It has to be able to run on different often used versions of blender (like the one of the Ubuntu repositories). That's my reason for using this version. An update to a newer version isn't a real solution for this specific problem cause if this addon is used by an user on another version of blender it still will misbehave. Mybe i'll have to use a workaround. Later i'll check the addon using some different blender versions. $\endgroup$ – thz Feb 14 '17 at 15:33
  • $\begingroup$ Operator.check, what a cool feature! $\endgroup$ – R. Navega Dec 18 '17 at 22:11
0
$\begingroup$

Like written in my comment i've written a workaround. The old popup is closed after short delay by a simulated press of the ESC-key. After a second short delay the cursor is placed on the position it was on the initial invoke of the popup. Then the popup is reopened after a third delay. Finally the cursorposition is restored after an last delay. Each delay takes 0.01 seconds.

Here's the code of the workaround (init.py):

import sys
if   sys.platform == 'linux' :
    from .lib import fake_input_x11 as fake_input
elif sys.platform == 'win32' :
    from .lib import fake_input_win as fake_input
elif sys.platform == 'darwin':
    from .lib import fake_input_mac as fake_input
else:
    from .lib import fake_input_x11 as fake_input

bpy.props.simple_edit_prefs_popup_shown  = False
bpy.props.simple_edit_prefs_popup_redraw = False

#....

class simple_edit_preferences(bpy.types.AddonPreferences):

    #....

    def update_prefs_popup(self, context):
        self.update_prefs(context)

        update_popup(self, context)

#....

def update_popup(self, context):
    if bpy.props.simple_edit_prefs_popup_shown and fake_input.usable:
        bpy.props.simple_edit_prefs_popup_redraw = True

        new_pos = fake_input.position()

        t = [time.time()]
        i = [0]

        handles = bpy.app.handlers.scene_update_post

        @bpy.app.handlers.persistent
        def on_scene_update(scene):
            if time.time()-t[0] > 0.01:
                t[0] = time.time()
                i[0] = i[0] + 1

                if   i[0]==1:
                    fake_input.esc()
                elif i[0]==2:
                    old_pos = bpy.props.simple_edit_prefs_popup_pos
                    fake_input.moveTo(old_pos[0], old_pos[1])
                elif i[0]==3:
                    bpy.ops.ui.simple_edit_simplify_ui_popup("INVOKE_DEFAULT")
                elif i[0]==4:
                    fake_input.moveTo(new_pos[0], new_pos[1])
                    bpy.props.simple_edit_prefs_popup_redraw = False

                    handles.remove(on_scene_update)

        handles.append(on_scene_update)


class UI_OT_simple_edit_simplify_ui_popup(bpy.types.Operator):
    """Simplify User Interface Popup"""
    bl_idname = "ui.simple_edit_simplify_ui_popup"
    bl_label = "Simplify User Interface"
    bl_description = "Show popup to simplify the user interface by removing areas, menu entries and other elements of the user interface"
    bl_options = {'REGISTER', 'UNDO'}


    def execute(self, context):
        if not bpy.props.simple_edit_prefs_popup_redraw:
            bpy.props.simple_edit_prefs_popup_shown = False
            bpy.ops.wm.save_userpref()
        return {'FINISHED'}

    def invoke(self, context, event):
        bpy.props.simple_edit_prefs_popup_shown = True
        bpy.props.simple_edit_prefs_popup_self  = self
        bpy.props.simple_edit_prefs_popup_pos   = fake_input.position()

        return context.window_manager.invoke_props_dialog(self, width=600)

    def draw(self, context):
        simple_edit_preferences.draw_menus(self.layout, context)

update_prefs_popup is called on each update of the relevant properties.

fake_input_x11.py:

@property
def usable():
    return True

import os
import sys

sys.path.append(os.path.dirname(__file__))
from Xlib.display import Display
from Xlib import X
from Xlib.ext.xtest import fake_input
from Xlib import XK

__display = Display(os.environ['DISPLAY'])

def position():
    pos = __display.screen().root.query_pointer()._data
    return pos["root_x"], pos["root_y"]

def moveTo(x, y):
    fake_input(__display, X.MotionNotify, x=x, y=y)
    __display.sync()

def keyDown(key):
    fake_input(__display, X.KeyPress, key)
    __display.sync()

def keyUp(key):
    fake_input(__display, X.KeyRelease, key)
    __display.sync()

def esc():
    key = __display.keysym_to_keycode(XK.string_to_keysym('Escape'))
    keyDown(key)
    keyUp  (key)

I've downloaded Xlib and added it to the lib-folder of the addon. The path of this folder has to be published in sys.path cause some modules of Xlib are doing something like import Xlib.

| improve this answer | |
$\endgroup$

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.