Ignore a BoolProperty from Undo?

i created a custom blender ui.
i know that normally we should register multiple panel and sub-panel but i decided to do things differently.

my UI is based on bool properties, like this below

enter image description here

prop stored in addon preferences

class SCATTER_AddonPref(AddonPreferences):
    bl_idname = __name__
    addon_prefs = bpy.context.preferences.addons[__name__].preferences

    scatter_sliders_display          : BoolProperty(name="",description="",default=False) 
    scatter_sliders_vgroup           : BoolProperty(name="",description="",default=False) 
    scatter_sliders_curv_is_open     : BoolProperty(name="",description="",default=False) 
    scatter_sliders_curv_adv_is_open : BoolProperty(name="",description="",default=False) 
    scatter_proxy_is_open            : BoolProperty(name="",description="",default=False)

and this is how i use it in the ui

layout.prop(addon_prefs,'scatter_camera_is_open',text="bla category",emboss=False,icon='BLENDER')
if addon_prefs.scatter_camera_is_open:
    layout.label(text="blablabla")

i think it is a really nice method. i already saw this used in many many case, but the problem as we saw in the gif is that it leave a trace in the undo history.

so is there’s a way to avoid this or am i screwed ?
anyhow i could ignore ctrl z with this specific property ?
for example, is it possible to create an operator that will toggle thoses addon pref on/off and will not show up in the history at all ?

A Long Shot:

class PDT_OT_Link(Operator):
    """Link from Library at Object's Origin."""

    bl_idname = "pdt.link"
    bl_label = "Link"
    bl_options = {"REGISTER", "UNDO"}

This operator allows “UNDO”, would not allowing this be an option, I don’t really know the answer to this but it may help…

Hello
3 years later, I am still stuck on this problem,

my_search_bar : bpy.props.StringProperty(name="Search Bar",options={'SKIP_UNDO'},)

Properties strictly used for GUI could greatly benefit from a “ignore history” flag, i wonder if this option already exists in a somewhat obscure part of the doc?

I did wonder if HIDDEN flags would help, it did not

is_property_hidden(property )
“Check if a property is hidden.” #ok but what does it implies ?

This is also a problem in main blender & UI lists

typically, the IntProperties used to get the active item will leave traces, and destroy the history of the user if he change his active item a too much

So we have 3 now use case of GUI Properties being problematic in the history:

  • Booleans for opening/closing ‘custom’ interface
  • search bars
  • Indexes of lists interface

You should be able to put runtime-related properties on bpy.types.WindowManager, since that’s one of the only data blocks excluded from being serialized. Which in theory makes them exempt from any undo.

1 Like

Hmm that could work assuming the user won’t mind his panels/GUi elements resetting on each session i guess :thinking: Thanks for the info I’ll try if it works

We are stuck on the UIList index problem tho, both in python and main blender, as they might need to be implemented outside

1 Like

The UIList active index can also be stored on the window manager to avoid undo.

As for syncing the runtime state, this is roughly what I’ve been doing the last few years:

Each time a runtime property is changed, it calls an update function that reads the runtime properties and stores the values in a json string, which is then stored in a property in my addon preferences. Something like this:

runtime_properties = ["prop_a", "prop_b", "prop_c", ...]

def serialize(self, context):
    data = {}
    for propname in runtime_properties:
        value = getattr(self, propname, None)
        if value is not None:
            data[propname] = value

    import json
    string_data = json.dumps(data)

    # Store the string in a StringProperty in my addon prefs
    prefs = get_addon_prefs()
    prefs.runtime_data = string_data  # StringProperty
    context.preferences.is_dirty = True

Optionally, you could avoid having to define a list of runtime properties and get them programmatically. To clarify, self in this context is the property group where the properties are stored:

def serialize(self, context):
    data = {}
    for propname in set(self.bl_rna.properties.keys()) - {'rna_type'}:
        ...
    # (rest is same as above)

Then, when the addon loads when Blender starts, I do the opposite in the class’ register callback.


class ADDON_PG_runtime(bpy.types.PropertyGroup):

    ...

    @classmethod
    def register(cls):
        import json

        prefs = get_addon_prefs()
        data = json.loads(prefs.string_data)
        wm = bpy.context.window_manager
        if isinstance(data, dict):
            for propname, value in data.items():
                # Assume the runtime property group is bpy.context.window_manager.runtime
                if hasattr(wm.runtime, propname):
                    setattr(wm.runtime, propname, value)

It’s not too much hassle to set up. Once the system is in place, it Just Works™.

Ha, nice work-around :slight_smile:
For UIList index attached to object for example, the workaround/implementation will start to become a bit dodgy

the “Double click to rename” issue I believe it’s a straight out a bug so i filled a report
https://developer.blender.org/T100200

1 Like