Button to collapse a menu from the end

Issue #728 resolved
Chuki Cicha created an issue

If I’m looking (for example) at my face units, and then I want to collapse the face units, I have to scroll all the way up to the “Face units” dropdown menu to collapse it, it would be nice to have a button at the end so we don’t have to scroll all the way up. It gets tedious when you have more than 100morphs under the same category…

Comments (16)

  1. Chuki Cicha reporter

    I know nothing about python, but when you create a button inside a panel, can’t you get the parent of it and call its close function or something like that?

  2. Xin

    I think a better solution would be to move those sliders to a UIList: https://docs.blender.org/api/current/bpy.types.UIList.html

    Then searching/filtering is built-in, and more compact than the current huge panel. You can search at any scroll depth unlike the current searching. It’s basically the same UI element used for Shape Keys.

    For an example Thomas, you can look at how UIList is implemented in the HD addon.

  3. Thomas Larsson repo owner

    Thank you for this, Xin. The standard morph panels now all use UILists. The custom morphs still use the old interface, because it does not seem easy to define and register UIList classes dynamically. The standard morphs types are all defined statically, even if they do not show up unless there are some morphs in them.

  4. Xin

    Thanks for the changes Thomas.

    I’m not sure I understand why it’s not possible to do it with the custom morphs. I assumed it was due to the “pin” operator needing extra information. So attached is one possible solution. I didn’t implement it on custom morphs, but the implementation only uses 1 UIList, and the pin operator was moved outside the list to resemble more how the Shape Keys panel works. It works on the active element in the list. Another advantage is that it frees some space in the UI.

    If what I assumed was right, this should be possible to implement on custom morphs too.

  5. Thomas Larsson repo owner

    With a single UIList filtering and resizing will affect all morph types. But that may be ok, I used a global variable for filtering before too.

    One could extract the extra info from the name of the indexing property. It is not so elegant but doable. Custom properties are trickier because the owner of the collection property is a property group DazCategory.

  6. Xin

    Oh ok, I don’t know what’s best in that case.

    As for the custom morphs, couldn’t they just share a UIList between all categories (not necessarily the same UIList used by the non-custom morphs)? you would create a box, and inside the box you draw the UIList by calling template_list() with the “morphs” of that category alone. You would need to create an index property in DazCategory, to pass it to template_list() so it can keep track of the active element from the “morphs” collection.


    Another thing, you might want to avoid unnecessary computations in any draw() functions since they are called a lot.

    So, for example, in draw_item() from DAZ_UL_Morphs, you would want to structure it this way to avoid doing computations when showFinalProps is False:

    def draw_item(self, context, layout, rig, morph, icon, active, indexProp):
        key = morph.name
        if key not in rig.keys():
            return
        split = layout.split(factor=0.8)
        if GS.showFinalProps:
            amt = self.getAmt(rig)
            final = finalProp(key)
            if final in amt.keys():
                split2 = split.split(factor=0.8)
                split2.prop(rig, propRef(key), text=morph.text)
                split2.label(text = "%.3f" % amt[final])
        else:
            split.prop(rig, propRef(key), text=morph.text)
        row = split.row()
        self.showBool(row, rig, key)
    

  7. Thomas Larsson repo owner

    It turned out to be tricky to communicate the content of the filter box to the buttons above the UIList. I’m using global variables, which seems to work but is not optimal and doesn’t handle advanced search options.

  8. Xin

    Thanks for the changes again Thomas.

    I think you could implement the filter_items() method of the UIList. That way for example, you could at the same time the filtering is done, keep track of those items which were filtered (maybe use a similar boolean array like you already use for the “active” properties?). This way, the filtering done to show items in the UIList and the filtering used by the operators is exactly the same (no need to reimplement searching).

    Look at the example here: https://docs.blender.org/api/current/bpy.types.UIList.html . Search “helper_funcs” for useful built-in functions you can use, you don’t need to reimplement the searching if you use those helper functions. The documentation for those helper functions is here, although it seems incomplete (the method “sort_items_by_name()” is missing): https://docs.blender.org/api/current/bpy.types.UI_UL_list.html

    Also, the HD addon has a custom filter_items() function, you can look there for an example too.

    Another idea: instead of creating a second boolean array to keep track of filtered items, create a method in the UIList class that performs the filtering and returns the flags array (“flt_flags” in the example in the docs). In turn, that method is called by both “filter_items()” and the operators. That method should use filter_items_by_name() internally so it resembles the built-in search of the UIList.


    Another thing you could find useful in the future: the first list returned by filter_items() marks the filtered items with a flag, and those flags are passed also to each item when being drawn with draw_item(), through the “flt_flag” argument. I don’t think it’s useful in this case, but good to keep in mind.

  9. Xin

    Oh good, that was fast.

    I don’t know if you caught the edit. If maintaining the flag arrays give you problems for some reason, keep the other possible solution in mind, the one in the paragraph that starts with “Another idea:” in the previous message.

  10. Xin

    Ok, the alternative wasn’t as simple as I thought it would be. Here is a .blend that implements that alternative, in case you find it useful in the future, or in case using globals causes some performance issues:

  11. Chuki Cicha reporter

    It’s amazing now, I also like that it now has the same size you left it when you close or change panel.

  12. Log in to comment