Last uiList patch (for now!): filtering and reordering of shown elements.
[blender.git] / release / scripts / startup / bl_ui / __init__.py
index df6247f65f57c8049ae78581c1e430bb1481ac83..ba256bdb6c894e1ca00278124abcccb1d51daf68 100644 (file)
@@ -142,6 +142,61 @@ def unregister():
 # Define a default UIList, when a list does not need any custom drawing...
 # Keep in sync with its #defined name in UI_interface.h
 class UI_UL_list(bpy.types.UIList):
-    pass
+    # These are common filtering or ordering operations (same as the default C ones!).
+    @staticmethod
+    def filter_items_by_name(pattern, bitflag, items, propname="name", flags=None, reverse=False):
+        """
+        Set FILTER_ITEM for items which name matches filter_name one (case-insensitive).
+        pattern is the filtering pattern.
+        propname is the name of the string property to use for filtering.
+        flags must be a list of integers the same length as items, or None!
+        return a list of flags (based on given flags if not None),
+               or an empty list if no flags were given and no filtering has been done.
+        """
+        import fnmatch
+
+        if not pattern:  # Empty pattern = no filtering!
+            return flags or []
+
+        if flags is None:
+            flags = [0] * len(items)
+        for idx, it in enumerate(items):
+            name = getattr(it, propname, None)
+            # Implicitly add heading/trailing wildcards if needed.
+            if pattern[0] != "*":
+                pattern = "*" + pattern
+            if pattern[-1] != "*":
+                pattern = pattern + "*"
+            # This is similar to a logical xor
+            if bool(name and fnmatch.fnmatch(name.lower(), pattern.lower())) is not bool(reverse):
+                flags[idx] |= bitflag
+        return flags
+
+    @staticmethod
+    def sort_items_helper(sort_data, key, reverse=False):
+        """
+        Common sorting utility. Returns a neworder list mapping org_idx -> new_idx.
+        sort_data must be an (unordered) list of tuples [(org_idx, ...), (org_idx, ...), ...].
+        key must be the same kind of callable you would use for sorted() builtin function.
+        reverse will reverse the sorting!
+        """
+        sort_data.sort(key=key, reverse=reverse)
+        neworder = [None] * len(sort_data)
+        for newidx, (orgidx, *_) in enumerate(sort_data):
+            neworder[orgidx] = newidx
+        return neworder
+
+    @classmethod
+    def sort_items_by_name(cls, items, propname="name"):
+        """
+        Re-order items using their names (case-insensitive).
+        propname is the name of the string property to use for sorting.
+        return a list mapping org_idx -> new_idx,
+               or an empty list if no sorting has been done.
+        """
+        neworder = [None] * len(items)
+        _sort = [(idx, getattr(it, propname, "")) for idx, it in enumerate(items)]
+        return cls.sort_items_helper(_sort, lambda e: e[1].lower())
+
 
 bpy.utils.register_class(UI_UL_list)