This commit frees list ui items from their dependencies to Panel, and hence from...
authorBastien Montagne <montagne29@wanadoo.fr>
Fri, 28 Dec 2012 09:20:16 +0000 (09:20 +0000)
committerBastien Montagne <montagne29@wanadoo.fr>
Fri, 28 Dec 2012 09:20:16 +0000 (09:20 +0000)
It introduces a new (py-extendable and registrable) RNA type, UIList (roughly similar to Panel one), which currently contains only "standard" list's scroll pos and size (but may be expended to include e.g. some filtering data, etc.). This now makes lists completely independent from Panels!

This UIList has a draw_item callback which allows to customize items' drawing from python, that all addons can now use. Incidentally, this also greatly simplifies the C code of this widget, as we do not code any "special case" here anymore!

To make all this work, other changes were also necessary:

* Now all buttons (uiBut struct) have a 'custom_data' void pointer, used currently to store the uiList struct associated with a given uiLayoutListBox.

* DynamicPaintSurface now exposes a new bool, use_color_preview (readonly), saying whether that surface has some 3D view preview data or not.

* UILayout class has now four new (static) functions, to get the actual icon of any RNA object (important e.g. with materials or textures), and to get an enum item's UI name, description and icon.

* UILayout's label() func now takes an optional 'icon_value' integer parameter, which if not zero will override the 'icon' one (mandatory to use "custom" icons as generated for material/texture/... previews).
  Note: not sure whether we should add that one to all UILayout's prop funcs?

Note: will update addons using template list asap.

36 files changed:
release/scripts/modules/bpy_types.py
release/scripts/startup/bl_ui/__init__.py
release/scripts/startup/bl_ui/properties_data_armature.py
release/scripts/startup/bl_ui/properties_data_mesh.py
release/scripts/startup/bl_ui/properties_mask_common.py
release/scripts/startup/bl_ui/properties_material.py
release/scripts/startup/bl_ui/properties_particle.py
release/scripts/startup/bl_ui/properties_physics_common.py
release/scripts/startup/bl_ui/properties_physics_dynamicpaint.py
release/scripts/startup/bl_ui/properties_render.py
release/scripts/startup/bl_ui/properties_scene.py
release/scripts/startup/bl_ui/properties_texture.py
release/scripts/startup/bl_ui/space_clip.py
release/scripts/startup/bl_ui/space_view3d_toolbar.py
source/blender/blenkernel/BKE_screen.h
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/UI_interface.h
source/blender/editors/include/UI_interface_icons.h
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_icons.c
source/blender/editors/interface/interface_intern.h
source/blender/editors/interface/interface_layout.c
source/blender/editors/interface/interface_templates.c
source/blender/editors/space_node/drawnode.c
source/blender/makesdna/DNA_screen_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/RNA_enum_types.h
source/blender/makesrna/intern/rna_dynamicpaint.c
source/blender/makesrna/intern/rna_ui.c
source/blender/makesrna/intern/rna_ui_api.c
source/blender/python/intern/bpy_rna.c
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index 11e1115fa4cec2500e192e4b06fcd34442863a58..1c861aa3be272f9815c5be7306fed5ef42b14531 100644 (file)
@@ -673,6 +673,10 @@ class Panel(StructRNA, _GenericUI, metaclass=RNAMeta):
     __slots__ = ()
 
 
+class UIList(StructRNA, _GenericUI, metaclass=RNAMeta):
+    __slots__ = ()
+
+
 class Header(StructRNA, _GenericUI, metaclass=RNAMeta):
     __slots__ = ()
 
index e4be84d53969ae67410a4d8e8455b77dfe18ecc9..aa1a8a9a25b9b24bfeec86977ee2921bc0a53770 100644 (file)
@@ -132,3 +132,9 @@ def register():
 
 def unregister():
     bpy.utils.unregister_module(__name__)
+
+# Define a default UIList, when a list does not need any custom drawing...
+class UI_UL_list(bpy.types.UIList):
+    pass
+
+bpy.utils.register_class(UI_UL_list)
index 845beb0f86232f950fa68014a9fde9b5ac413afd..1643210704e8a97176d2b53af008f070c98f9fef 100644 (file)
@@ -124,7 +124,7 @@ class DATA_PT_bone_groups(ArmatureButtonsPanel, Panel):
         rows = 2
         if group:
             rows = 5
-        row.template_list(pose, "bone_groups", pose.bone_groups, "active_index", rows=rows)
+        row.template_list("UI_UL_list", "", pose, "bone_groups", pose.bone_groups, "active_index", rows=rows)
 
         col = row.column(align=True)
         col.active = (ob.proxy is None)
@@ -184,7 +184,7 @@ class DATA_PT_pose_library(ArmatureButtonsPanel, Panel):
         if poselib:
             # list of poses in pose library
             row = layout.row()
-            row.template_list(poselib, "pose_markers", poselib.pose_markers, "active_index", rows=5)
+            row.template_list("UI_UL_list", "", poselib, "pose_markers", poselib.pose_markers, "active_index", rows=5)
 
             # column of operators for active pose
             # - goes beside list
index e33bed7ec6d66f70c503e40cbcea2e0c4bb77c97..7a7c847f0405656f84e5aae716e5d8f1bd04d044 100644 (file)
@@ -18,7 +18,7 @@
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Menu, Panel, UIList
 from rna_prop_ui import PropertyPanel
 
 
@@ -54,6 +54,57 @@ class MESH_MT_shape_key_specials(Menu):
         layout.operator("object.shape_key_add", icon='ZOOMIN', text="New Shape From Mix").from_mix = True
 
 
+class MESH_UL_vgroups(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.VertexGroup):
+            return
+        vgroup = item
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(vgroup.name, icon_value=icon)
+            icon = 'LOCKED' if vgroup.lock_weight else 'UNLOCKED'
+            layout.prop(vgroup, "lock_weight", text="", icon=icon, emboss=False)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+
+class MESH_UL_shape_keys(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.ShapeKey):
+            return
+        obj = active_data
+        key = data
+        key_block = item
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            split = layout.split(0.66, False)
+            split.label(item.name, icon_value=icon)
+            row = split.row(True)
+            if key_block.mute or (obj.mode == 'EDIT' and not (obj.use_shape_key_edit_mode and obj.type == 'MESH')):
+                row.active = False
+            if not item.relative_key or index > 0:
+                row.prop(key_block, "value", text="", emboss=False)
+            else:
+                row.label("")
+            row.prop(key_block, "mute", text="", emboss=False)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+
+class MESH_UL_uvmaps_vcols(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, (bpy.types.MeshTexturePolyLayer, bpy.types.MeshLoopColorLayer)):
+            print(item.__class__)
+            return
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(item.name, icon_value=icon)
+            icon = 'RESTRICT_RENDER_OFF' if item.active_render else 'RESTRICT_RENDER_ON'
+            layout.prop(item, "active_render", text="", icon=icon, emboss=False)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+
 class MeshButtonsPanel():
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -144,7 +195,8 @@ class DATA_PT_vertex_groups(MeshButtonsPanel, Panel):
             rows = 5
 
         row = layout.row()
-        row.template_list(ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows)
+        row.template_list("MESH_UL_vgroups", "", ob, "vertex_groups", ob.vertex_groups, "active_index", rows=rows)
+
 
         col = row.column(align=True)
         col.operator("object.vertex_group_add", icon='ZOOMIN', text="")
@@ -202,7 +254,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
         rows = 2
         if kb:
             rows = 5
-        row.template_list(key, "key_blocks", ob, "active_shape_key_index", rows=rows)
+        row.template_list("MESH_UL_shape_keys", "", key, "key_blocks", ob, "active_shape_key_index", rows=rows)
 
         col = row.column()
 
@@ -282,7 +334,7 @@ class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
         row = layout.row()
         col = row.column()
 
-        col.template_list(me, "uv_textures", me.uv_textures, "active_index", rows=2)
+        col.template_list("MESH_UL_uvmaps_vcols", "", me, "uv_textures", me.uv_textures, "active_index", rows=2)
 
         col = row.column(align=True)
         col.operator("mesh.uv_texture_add", icon='ZOOMIN', text="")
@@ -305,7 +357,7 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, Panel):
         row = layout.row()
         col = row.column()
 
-        col.template_list(me, "vertex_colors", me.vertex_colors, "active_index", rows=2)
+        col.template_list("MESH_UL_uvmaps_vcols", "", me, "vertex_colors", me.vertex_colors, "active_index", rows=2)
 
         col = row.column(align=True)
         col.operator("mesh.vertex_color_add", icon='ZOOMIN', text="")
index 208b0a63075b0f30c48276d5e0f93241cb8dfb4b..ea04b79357ee84777f28864bf91b031db25fc669 100644 (file)
 # menus are referenced `as is`
 
 import bpy
-from bpy.types import Menu
+from bpy.types import Menu, UIList
+
+
+class MASK_UL_layers(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.MaskLayer):
+            return
+        mask = item
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            split = layout.split()
+            split.label(mask.name, icon_value=icon)
+            row = split.row(align=True)
+            row.prop(mask, "alpha", text="", emboss=False)
+            row.prop(mask, "hide", text="", emboss=False)
+            row.prop(mask, "hide_select", text="", emboss=False)
+            row.prop(mask, "hide_render", text="", emboss=False)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
 
 
 class MASK_PT_mask:
@@ -69,8 +87,7 @@ class MASK_PT_layers:
         rows = 5 if active_layer else 2
 
         row = layout.row()
-        row.template_list(mask, "layers",
-                          mask, "active_layer_index", rows=rows)
+        row.template_list("MASK_UL_layers", "", mask, "layers", mask, "active_layer_index", rows=rows)
 
         sub = row.column(align=True)
 
index 951644db752fd350a28b6af66ccd08b950f78e46..df676499cfb64b1fa94bfaf54452651fdd535381 100644 (file)
@@ -18,7 +18,7 @@
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Menu, Panel, UIList
 from rna_prop_ui import PropertyPanel
 
 
@@ -69,6 +69,26 @@ class MATERIAL_MT_specials(Menu):
         layout.operator("material.paste", icon='PASTEDOWN')
 
 
+class MATERIAL_UL_matslots(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.MaterialSlot):
+            return
+        ob = data
+        slot = item
+        ma = slot.material
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(ma.name if ma else "", icon_value=icon)
+            if ma and not context.scene.render.use_shading_nodes:
+                manode = ma.active_node_material
+                if manode:
+                    layout.label("Node %s" % manode.name, icon_value=layout.icon(manode))
+                elif ma.use_nodes:
+                    layout.label("Node <none>")
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+
 class MaterialButtonsPanel():
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -104,7 +124,7 @@ class MATERIAL_PT_context_material(MaterialButtonsPanel, Panel):
         if ob:
             row = layout.row()
 
-            row.template_list(ob, "material_slots", ob, "active_material_index", rows=2)
+            row.template_list("MATERIAL_UL_matslots", "", ob, "material_slots", ob, "active_material_index", rows=2)
 
             col = row.column(align=True)
             col.operator("object.material_slot_add", icon='ZOOMIN', text="")
index 2c2ced5db0c51cb6221a5eedc829b83975949328..90dcf59413708a3c2c597cdaae6ebc5492473417 100644 (file)
@@ -96,7 +96,7 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, Panel):
         if ob:
             row = layout.row()
 
-            row.template_list(ob, "particle_systems", ob.particle_systems, "active_index", rows=2)
+            row.template_list("UI_UL_list", "", ob, "particle_systems", ob.particle_systems, "active_index", rows=2)
 
             col = row.column(align=True)
             col.operator("object.particle_system_add", icon='ZOOMIN', text="")
@@ -636,7 +636,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel):
                 layout.label(text="Fluid interaction:")
 
             row = layout.row()
-            row.template_list(psys, "targets", psys, "active_particle_target_index")
+            row.template_list("UI_UL_list", "", psys, "targets", psys, "active_particle_target_index")
 
             col = row.column()
             sub = col.row()
@@ -702,7 +702,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
 
         # Currently boids can only use the first state so these are commented out for now.
         #row = layout.row()
-        #row.template_list(boids, "states", boids, "active_boid_state_index", compact="True")
+        #row.template_list("UI_UL_list", "", boids, "states", boids, "active_boid_state_index", compact="True")
         #col = row.row()
         #sub = col.row(align=True)
         #sub.operator("boid.state_add", icon='ZOOMIN', text="")
@@ -723,7 +723,7 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel):
             row.label(text="")
 
         row = layout.row()
-        row.template_list(state, "rules", state, "active_boid_rule_index")
+        row.template_list("UI_UL_list", "", state, "rules", state, "active_boid_rule_index")
 
         col = row.column()
         sub = col.row()
@@ -886,7 +886,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel):
 
             if part.use_group_count and not part.use_whole_group:
                 row = layout.row()
-                row.template_list(part, "dupli_weights", part, "active_dupliweight_index")
+                row.template_list("UI_UL_list", "", part, "dupli_weights", part, "active_dupliweight_index")
 
                 col = row.column()
                 sub = col.row()
index 405e877d1e225d544a6f9caff36716468925ecdc..b70ff322765a0335f74388b9c38cb0ea128d1caa 100644 (file)
@@ -85,7 +85,7 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
     layout.context_pointer_set("point_cache", cache)
 
     row = layout.row()
-    row.template_list(cache, "point_caches", cache.point_caches, "active_index", rows=2)
+    row.template_list("UI_UL_list", "", cache, "point_caches", cache.point_caches, "active_index", rows=2)
     col = row.column(align=True)
     col.operator("ptcache.add", icon='ZOOMIN', text="")
     col.operator("ptcache.remove", icon='ZOOMOUT', text="")
index 1df2936b2d45bab7d8be8765df6deb37e97f1c54..b102f1b09d053f33f6d4581075b6155229ddce00 100644 (file)
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Panel
+from bpy.types import Panel, UIList
 
 from bl_ui.properties_physics_common import (point_cache_ui,
                                              effector_weights_ui,
                                              )
 
 
+class PHYSICS_UL_dynapaint_surfaces(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.DynamicPaintSurface):
+            return
+        surf = item
+        sticon = layout.enum_item_icon(surf, "surface_type", surf.surface_type)
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            row = layout.row(align=True)
+            row.label(text="", icon_value=icon)
+            row.label(text=surf.name, icon_value=sticon)
+            row = layout.row(align=True)
+            if surf.use_color_preview:
+                row.prop(surf, "show_preview", text="", emboss=False,
+                         icon='RESTRICT_VIEW_OFF' if surf.show_preview else 'RESTRICT_VIEW_ON')
+            row.prop(surf, "is_active", text="")
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            row = layout.row(align=True)
+            row.label(text="", icon_value=icon)
+            row.label(text="", icon_value=sticon)
+
+
 class PhysicButtonsPanel():
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -58,7 +80,8 @@ class PHYSICS_PT_dynamic_paint(PhysicButtonsPanel, Panel):
                 surface = canvas.canvas_surfaces.active
 
                 row = layout.row()
-                row.template_list(canvas, "canvas_surfaces", canvas.canvas_surfaces, "active_index", rows=2)
+                row.template_list("PHYSICS_UL_dynapaint_surfaces", "", canvas, "canvas_surfaces",
+                                   canvas.canvas_surfaces, "active_index", rows=2)
 
                 col = row.column(align=True)
                 col.operator("dpaint.surface_slot_add", icon='ZOOMIN', text="")
index 3fdcf946180f35b3965997e46ceaf25f21038607..6f0cf6bc69104605f9f8bccf0dd9618a467bd7c4 100644 (file)
@@ -19,7 +19,7 @@
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Menu, Panel, UIList
 
 
 class RENDER_MT_presets(Menu):
@@ -43,6 +43,24 @@ class RENDER_MT_framerate_presets(Menu):
     draw = Menu.draw_preset
 
 
+class RENDER_UL_renderlayers(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.SceneRenderLayer):
+            return
+        layer = item
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(layer.name, icon_value=icon)
+            layout.prop(layer, "use", text="", index=index)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+#      else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
+#              uiItemL(sub, name, icon);
+#              uiBlockSetEmboss(block, UI_EMBOSS);
+#              uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
+#      }
+
 class RenderButtonsPanel():
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -84,7 +102,7 @@ class RENDER_PT_layers(RenderButtonsPanel, Panel):
         rd = scene.render
 
         row = layout.row()
-        row.template_list(rd, "layers", rd.layers, "active_index", rows=2)
+        row.template_list("RENDER_UL_renderlayers", "", rd, "layers", rd.layers, "active_index", rows=2)
 
         col = row.column(align=True)
         col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
index 518b253d0b02fae20eac476f0269de36395caa01..100c7d93c775ba2990e0526e8979ed156152859c 100644 (file)
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Panel
+from bpy.types import Panel, UIList
 from rna_prop_ui import PropertyPanel
 
 
+class SCENE_UL_keying_set_paths(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not isinstance(item, bpy.types.KeyingSetPath):
+            return
+        kspath = item
+        icon = layout.enum_item_icon(kspath, "id_type", kspath.id_type)
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(kspath.data_path, icon_value=icon)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+
 class SceneButtonsPanel():
     bl_space_type = 'PROPERTIES'
     bl_region_type = 'WINDOW'
@@ -107,7 +120,7 @@ class SCENE_PT_keying_sets(SceneButtonsPanel, Panel):
         row = layout.row()
 
         col = row.column()
-        col.template_list(scene, "keying_sets", scene.keying_sets, "active_index", rows=2)
+        col.template_list("UI_UL_list", "", scene, "keying_sets", scene.keying_sets, "active_index", rows=2)
 
         col = row.column(align=True)
         col.operator("anim.keying_set_add", icon='ZOOMIN', text="")
@@ -151,7 +164,7 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel, Panel):
         row = layout.row()
 
         col = row.column()
-        col.template_list(ks, "paths", ks.paths, "active_index", rows=2)
+        col.template_list("SCENE_UL_keying_set_paths", "", ks, "paths", ks.paths, "active_index", rows=2)
 
         col = row.column(align=True)
         col.operator("anim.keying_set_path_add", icon='ZOOMIN', text="")
index e623d034b483e0ec277e4c6247434c51ae10d99c..33b8e126398de0349d145c2b5336fe4f4ac9ecd9 100644 (file)
@@ -18,7 +18,7 @@
 
 # <pep8 compliant>
 import bpy
-from bpy.types import Menu, Panel
+from bpy.types import Menu, Panel, UIList
 
 from bpy.types import (Brush,
                        Lamp,
@@ -55,6 +55,23 @@ class TEXTURE_MT_envmap_specials(Menu):
         layout.operator("texture.envmap_clear", icon='FILE_REFRESH')
         layout.operator("texture.envmap_clear_all", icon='FILE_REFRESH')
 
+
+class TEXTURE_UL_texslots(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not (item is None or isinstance(item, bpy.types.MaterialTextureSlot)):
+            return
+        ma = data
+        slot = item
+        tex = slot.texture if slot else None
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(tex.name if tex else "", icon_value=icon)
+            if tex:
+                layout.prop(ma, "use_textures", text="", index=index)
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon_value=icon)
+
+
 from bl_ui.properties_material import active_node_mat
 
 
@@ -142,7 +159,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, Panel):
         if tex_collection:
             row = layout.row()
 
-            row.template_list(idblock, "texture_slots", idblock, "active_texture_index", rows=2)
+            row.template_list("TEXTURE_UL_texslots", "", idblock, "texture_slots", idblock, "active_texture_index", rows=2)
 
             col = row.column(align=True)
             col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
index cb88226b55a21cea07287325340fb495a84096dc..cf5b94277e7560e6bb17eaab8cafe0416486ff9c 100644 (file)
 # <pep8-80 compliant>
 
 import bpy
-from bpy.types import Panel, Header, Menu
+from bpy.types import Panel, Header, Menu, UIList
+
+
+class CLIP_UL_tracking_objects(UIList):
+    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+        if not (item is None or isinstance(item, bpy.types.MovieTrackingObject)):
+            return
+        tobj = item
+        if self.layout_type in {'DEFAULT', 'COMPACT'}:
+            layout.label(tobj.name, icon='CAMERA_DATA' if tobj.is_camera else 'OBJECT_DATA')
+        elif self.layout_type in {'GRID'}:
+            layout.alignment = 'CENTER'
+            layout.label("", icon='CAMERA_DATA' if tobj.is_camera else 'OBJECT_DATA')
 
 
 class CLIP_HT_header(Header):
@@ -471,8 +483,7 @@ class CLIP_PT_objects(CLIP_PT_clip_view_panel, Panel):
         tracking = sc.clip.tracking
 
         row = layout.row()
-        row.template_list(tracking, "objects",
-                          tracking, "active_object_index", rows=3)
+        row.template_list("CLIP_UL_tracking_objects", "", tracking, "objects", tracking, "active_object_index", rows=3)
 
         sub = row.column(align=True)
 
@@ -728,7 +739,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel):
         layout.active = stab.use_2d_stabilization
 
         row = layout.row()
-        row.template_list(stab, "tracks", stab, "active_track_index", rows=3)
+        row.template_list("UI_UL_list", "", stab, "tracks", stab, "active_track_index", rows=3)
 
         sub = row.column(align=True)
 
index 09b32cd0c5615d6e3fb752d0fe7bab03db920ad0..fb5e4a56aa1e6fbe7dd554d6bad5fa088a45f528 100644 (file)
@@ -1167,7 +1167,8 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
         if pe.type == 'PARTICLES':
             if ob.particle_systems:
                 if len(ob.particle_systems) > 1:
-                    layout.template_list(ob, "particle_systems", ob.particle_systems, "active_index", rows=2, maxrows=3)
+                    layout.template_list("UI_UL_list", "", ob, "particle_systems",
+                                         ob.particle_systems, "active_index", rows=2, maxrows=3)
 
                 ptcache = ob.particle_systems.active.point_cache
         else:
@@ -1176,7 +1177,8 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, Panel):
                     ptcache = md.point_cache
 
         if ptcache and len(ptcache.point_caches) > 1:
-            layout.template_list(ptcache, "point_caches", ptcache.point_caches, "active_index", rows=2, maxrows=3)
+            layout.template_list("UI_UL_list", "", ptcache, "point_caches", ptcache.point_caches, "active_index",
+                                 rows=2, maxrows=3)
 
         if not pe.is_editable:
             layout.label(text="Point cache must be baked")
index 8aa08beec5712688d3c71efdbb802d9aea4cc857..3c6f886b59a42e835c5003ada83ab39cb141400e 100644 (file)
@@ -46,6 +46,7 @@ struct bContext;
 struct bContextDataResult;
 struct bScreen;
 struct uiLayout;
+struct uiList;
 struct uiMenuItem;
 struct wmKeyConfig;
 struct wmNotifier;
@@ -181,6 +182,23 @@ typedef struct PanelType {
        ExtensionRNA ext;
 } PanelType;
 
+/* uilist types */
+
+/* draw an item in the uiList */
+typedef void (*uiListDrawItemFunc)(struct uiList *, struct bContext *, struct uiLayout *, struct PointerRNA *,
+                                   struct PointerRNA *, int, struct PointerRNA *, const char *, int);
+
+typedef struct uiListType {
+       struct uiListType *next, *prev;
+
+       char idname[BKE_ST_MAXNAME];            /* unique name */
+
+       uiListDrawItemFunc draw_item;
+
+       /* RNA integration */
+       ExtensionRNA ext;
+} uiListType;
+
 /* header types */
 
 typedef struct HeaderType {
index e27f2464f9b65c17cdca7be6e83dd6464a67e592..520e4fd2c3998e814f9082fe5c87b984e030ab5d 100644 (file)
@@ -5832,6 +5832,7 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
 static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
 {
        Panel *pa;
+       uiList *uilst;
 
        link_list(fd, &ar->panels);
 
@@ -5841,7 +5842,13 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
                pa->activedata = NULL;
                pa->type = NULL;
        }
-       
+
+       link_list(fd, &ar->uiLists);
+
+       for (uilst = ar->uiLists.first; uilst; uilst = uilst->next) {
+               uilst->type = NULL;
+       }
+
        ar->regiondata = newdataadr(fd, ar->regiondata);
        if (ar->regiondata) {
                if (spacetype == SPACE_VIEW3D) {
index 61b75a493743ce442ef379bb6fe80e454719edbe..1b28504700b7570c918a2d3b6edf17ae54b47197 100644 (file)
@@ -2395,6 +2395,7 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                for (sa= sc->areabase.first; sa; sa= sa->next) {
                        SpaceLink *sl;
                        Panel *pa;
+                       uiList *uilst;
                        ARegion *ar;
                        
                        writestruct(wd, DATA, "ScrArea", 1, sa);
@@ -2404,6 +2405,9 @@ static void write_screens(WriteData *wd, ListBase *scrbase)
                                
                                for (pa= ar->panels.first; pa; pa= pa->next)
                                        writestruct(wd, DATA, "Panel", 1, pa);
+                               
+                               for (uilst = ar->uiLists.first; uilst; uilst = uilst->next)
+                                       writestruct(wd, DATA, "uiList", 1, uilst);
                        }
                        
                        sl= sa->spacedata.first;
index 9a04138e72eedfb3fcd73a19b444d6cebf68a10a..281d80a9d2b2a1756aa769342c5816e9c4335ee8 100644 (file)
@@ -56,6 +56,7 @@ struct PropertyRNA;
 struct ReportList;
 struct rcti;
 struct rctf;
+struct uiList;
 struct uiStyle;
 struct uiFontStyle;
 struct uiWidgetColors;
@@ -779,7 +780,7 @@ uiLayout *uiLayoutRow(uiLayout *layout, int align);
 uiLayout *uiLayoutColumn(uiLayout *layout, int align);
 uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, int align);
 uiLayout *uiLayoutBox(uiLayout *layout);
-uiLayout *uiLayoutListBox(uiLayout *layout, struct PointerRNA *ptr, struct PropertyRNA *prop,
+uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *uilst, struct PointerRNA *ptr, struct PropertyRNA *prop,
                           struct PointerRNA *actptr, struct PropertyRNA *actprop);
 uiLayout *uiLayoutAbsolute(uiLayout *layout, int align);
 uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align);
@@ -825,7 +826,9 @@ void uiTemplateTextureImage(uiLayout *layout, struct bContext *C, struct Tex *te
 void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
 void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
 
-void uiTemplateList(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *activeptr, const char *activeprop, const char *prop_list, int rows, int maxrows, int type);
+void uiTemplateList(uiLayout *layout, struct bContext *C, const char *listtype_name, const char *list_id,
+                    struct PointerRNA *dataptr, const char *propname, struct PointerRNA *active_dataptr,
+                    const char *active_propname, int rows, int maxrows, int layout_type);
 void uiTemplateNodeLink(uiLayout *layout, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
 void uiTemplateNodeView(uiLayout *layout, struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input);
 void uiTemplateTextureUser(uiLayout *layout, struct bContext *C);
index aa94bdec724a1e9c33426f506cab45ed2fa5feb5..f578d68b852311a81ab148ca6b89b203ef775ce4 100644 (file)
 #ifndef __UI_INTERFACE_ICONS_H__
 #define __UI_INTERFACE_ICONS_H__
 
+struct bContext;
 struct Image;
 struct ImBuf;
 struct World;
 struct Tex;
 struct Lamp;
 struct Material;
+struct PointerRNA;
 
 typedef struct IconFile {
        struct IconFile *next, *prev;
@@ -74,5 +76,6 @@ void UI_icons_free_drawinfo(void *drawinfo);
 struct ListBase *UI_iconfile_list(void);
 int UI_iconfile_get_index(const char *filename);
 
+int UI_rnaptr_icon_get(struct bContext *C, struct PointerRNA *ptr, int rnaicon, int big);
 
 #endif /*  __UI_INTERFACE_ICONS_H__ */
index 9988224e0ab62b5da52f4e3e5bb6ed987bc5abb2..ee6916822f0ac15bb29cc54db42e10cdf08ea81e 100644 (file)
@@ -44,6 +44,7 @@
 
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
@@ -6094,63 +6095,65 @@ static int ui_handle_list_event(bContext *C, wmEvent *event, ARegion *ar)
        int value, min, max;
 
        if (but && (event->val == KM_PRESS)) {
-               Panel *pa = but->block->panel;
+               uiList *uilst = but->custom_data;
 
-               if (ELEM(event->type, UPARROWKEY, DOWNARROWKEY) ||
-                   ((ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
-               {
-                       /* activate up/down the list */
-                       value = RNA_property_int_get(&but->rnapoin, but->rnaprop);
-
-                       if (ELEM(event->type, UPARROWKEY, WHEELUPMOUSE))
-                               value--;
-                       else
-                               value++;
-
-                       CLAMP(value, 0, pa->list_last_len - 1);
-
-                       if (value < pa->list_scroll)
-                               pa->list_scroll = value;
-                       else if (value >= pa->list_scroll + pa->list_size)
-                               pa->list_scroll = value - pa->list_size + 1;
+               if (uilst) {
+                       if (ELEM(event->type, UPARROWKEY, DOWNARROWKEY) ||
+                               ((ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->alt)))
+                       {
+                               /* activate up/down the list */
+                               value = RNA_property_int_get(&but->rnapoin, but->rnaprop);
 
-                       RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
-                       value = CLAMPIS(value, min, max);
+                               if (ELEM(event->type, UPARROWKEY, WHEELUPMOUSE))
+                                       value--;
+                               else
+                                       value++;
 
-                       RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
-                       RNA_property_update(C, &but->rnapoin, but->rnaprop);
-                       ED_region_tag_redraw(ar);
+                               CLAMP(value, 0, uilst->list_last_len - 1);
 
-                       retval = WM_UI_HANDLER_BREAK;
-               }
-               else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) {
-                       /* silly replacement for proper grip */
-                       if (pa->list_grip_size == 0)
-                               pa->list_grip_size = pa->list_size;
+                               if (value < uilst->list_scroll)
+                                       uilst->list_scroll = value;
+                               else if (value >= uilst->list_scroll + uilst->list_size)
+                                       uilst->list_scroll = value - uilst->list_size + 1;
 
-                       if (event->type == WHEELUPMOUSE)
-                               pa->list_grip_size--;
-                       else
-                               pa->list_grip_size++;
+                               RNA_property_int_range(&but->rnapoin, but->rnaprop, &min, &max);
+                               value = CLAMPIS(value, min, max);
 
-                       pa->list_grip_size = MAX2(pa->list_grip_size, 1);
+                               RNA_property_int_set(&but->rnapoin, but->rnaprop, value);
+                               RNA_property_update(C, &but->rnapoin, but->rnaprop);
+                               ED_region_tag_redraw(ar);
 
-                       ED_region_tag_redraw(ar);
+                               retval = WM_UI_HANDLER_BREAK;
+                       }
+                       else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE) && event->shift) {
+                               /* silly replacement for proper grip */
+                               if (uilst->list_grip_size == 0)
+                                       uilst->list_grip_size = uilst->list_size;
 
-                       retval = WM_UI_HANDLER_BREAK;
-               }
-               else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
-                       if (pa->list_last_len > pa->list_size) {
-                               /* list template will clamp */
                                if (event->type == WHEELUPMOUSE)
-                                       pa->list_scroll--;
+                                       uilst->list_grip_size--;
                                else
-                                       pa->list_scroll++;
+                                       uilst->list_grip_size++;
+
+                               uilst->list_grip_size = MAX2(uilst->list_grip_size, 1);
 
                                ED_region_tag_redraw(ar);
 
                                retval = WM_UI_HANDLER_BREAK;
                        }
+                       else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+                               if (uilst->list_last_len > uilst->list_size) {
+                                       /* list template will clamp */
+                                       if (event->type == WHEELUPMOUSE)
+                                               uilst->list_scroll--;
+                                       else
+                                               uilst->list_scroll++;
+
+                                       ED_region_tag_redraw(ar);
+
+                                       retval = WM_UI_HANDLER_BREAK;
+                               }
+                       }
                }
        }
 
index 2928a5607c0573bed500543c6c7c76d8b0e26040..31d1ad7a955fe679bcb83eb38ed29f0522c35d88 100644 (file)
@@ -49,6 +49,7 @@
 #include "BLI_utildefines.h"
 
 #include "DNA_brush_types.h"
+#include "DNA_dynamicpaint_types.h"
 #include "DNA_object_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_space_types.h"
@@ -1179,6 +1180,44 @@ int ui_id_icon_get(bContext *C, ID *id, int big)
        return iconid;
 }
 
+int UI_rnaptr_icon_get(bContext *C, PointerRNA *ptr, int rnaicon, int big)
+{
+       ID *id = NULL;
+
+       if (!ptr->data)
+               return rnaicon;
+
+       /* try ID, material, texture or dynapaint slot */
+       if (RNA_struct_is_ID(ptr->type)) {
+               id = ptr->id.data;
+       }
+       else if (RNA_struct_is_a(ptr->type, &RNA_MaterialSlot)) {
+               id = RNA_pointer_get(ptr, "material").data;
+       }
+       else if (RNA_struct_is_a(ptr->type, &RNA_TextureSlot)) {
+               id = RNA_pointer_get(ptr, "texture").data;
+       }
+       else if (RNA_struct_is_a(ptr->type, &RNA_DynamicPaintSurface)) {
+               DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+
+               if (surface->format == MOD_DPAINT_SURFACE_F_PTEX)
+                       return ICON_TEXTURE_SHADED;
+               else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX)
+                       return ICON_OUTLINER_DATA_MESH;
+               else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ)
+                       return ICON_FILE_IMAGE;
+       }
+
+       /* get icon from ID */
+       if (id) {
+               int icon = ui_id_icon_get(C, id, big);
+
+               return icon ? icon : rnaicon;
+       }
+
+       return rnaicon;
+}
+
 static void icon_draw_at_size(float x, float y, int icon_id, float aspect, float alpha, enum eIconSizes size, int nocreate)
 {
        int draw_size = get_draw_size(size);
index f088b3a54f40efbc5a62aa898ed14996bb8f6161..8341307481d433cbfd8e3bc6ef03f6ebb441e177 100644 (file)
@@ -271,6 +271,9 @@ struct uiBut {
        /* active button data */
        struct uiHandleButtonData *active;
 
+       /* Custom button data. */
+       void *custom_data;
+
        char *editstr;
        double *editval;
        float *editvec;
index 2ba4c1355c07fe80708f31b621bbd73dfbc519ff..19b44422ac0d9f04261851125489bde877ea4ca3 100644 (file)
@@ -2308,11 +2308,14 @@ uiLayout *uiLayoutBox(uiLayout *layout)
        return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
 }
 
-uiLayout *uiLayoutListBox(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr, PropertyRNA *actprop)
+uiLayout *uiLayoutListBox(uiLayout *layout, uiList *uilist, PointerRNA *ptr, PropertyRNA *prop, PointerRNA *actptr,
+                          PropertyRNA *actprop)
 {
        uiLayoutItemBx *box = ui_layout_box(layout, LISTBOX);
        uiBut *but = box->roundbox;
 
+       but->custom_data = uilist;
+
        but->rnasearchpoin = *ptr;
        but->rnasearchprop = prop;
        but->rnapoin = *actptr;
index 5145c28a2cd7d4e75f3802486c245e9a62cc509d..34f325abe76513ef63c42a7e80413a6e7bdef50f 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_anim_types.h"
 #include "DNA_dynamicpaint_types.h"
-#include "DNA_key_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_object_types.h"
-#include "DNA_userdef_types.h"
 
 #include "BLI_utildefines.h"
 #include "BLI_string.h"
 #include "BLI_ghash.h"
 #include "BLI_rect.h"
 
+#include "BLF_api.h"
 #include "BLF_translation.h"
 
 #include "BKE_animsys.h"
@@ -59,6 +57,7 @@
 #include "BKE_displist.h"
 #include "BKE_sca.h"
 #include "BKE_scene.h"
+#include "BKE_screen.h"
 
 #include "ED_screen.h"
 #include "ED_object.h"
 #include "WM_types.h"
 
 #include "UI_interface.h"
+#include "UI_interface_icons.h"
 #include "interface_intern.h"
 
-#include "BLF_api.h"
-#include "BLF_translation.h"
-
 void UI_template_fix_linking(void)
 {
 }
@@ -2331,254 +2328,28 @@ void uiTemplateGameStates(uiLayout *layout, PointerRNA *ptr, const char *propnam
 
 
 /************************* List Template **************************/
-
-static int list_item_icon_get(bContext *C, PointerRNA *itemptr, int rnaicon, int big)
+static void uilist_draw_item_default(struct uiList *uilst, struct bContext *UNUSED(C), struct uiLayout *layout,
+                                     struct PointerRNA *UNUSED(dataptr), struct PointerRNA *itemptr, int icon,
+                                     struct PointerRNA *UNUSED(active_dataptr), const char *UNUSED(active_propname),
+                                     int UNUSED(index))
 {
-       ID *id = NULL;
-       int icon;
-
-       if (!itemptr->data)
-               return rnaicon;
-
-       /* try ID, material or texture slot */
-       if (RNA_struct_is_ID(itemptr->type)) {
-               id = itemptr->id.data;
-       }
-       else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
-               id = RNA_pointer_get(itemptr, "material").data;
-       }
-       else if (RNA_struct_is_a(itemptr->type, &RNA_TextureSlot)) {
-               id = RNA_pointer_get(itemptr, "texture").data;
-       }
-       else if (RNA_struct_is_a(itemptr->type, &RNA_DynamicPaintSurface)) {
-               DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
-
-               if (surface->format == MOD_DPAINT_SURFACE_F_PTEX) return ICON_TEXTURE_SHADED;
-               else if (surface->format == MOD_DPAINT_SURFACE_F_VERTEX) return ICON_OUTLINER_DATA_MESH;
-               else if (surface->format == MOD_DPAINT_SURFACE_F_IMAGESEQ) return ICON_FILE_IMAGE;
-       }
-
-       /* get icon from ID */
-       if (id) {
-               icon = ui_id_icon_get(C, id, big);
-
-               if (icon)
-                       return icon;
-       }
-
-       return rnaicon;
-}
-
-static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, PointerRNA *itemptr, int i,
-                          int rnaicon, PointerRNA *activeptr, PropertyRNA *activeprop, const char *prop_list_id)
-{
-       uiBlock *block = uiLayoutGetBlock(layout);
-       uiBut *but;
-       uiLayout *split, *overlap, *sub, *row;
        char *namebuf;
        const char *name;
-       int icon;
-
-       overlap = uiLayoutOverlap(layout);
-
-       /* list item behind label & other buttons */
-       sub = uiLayoutRow(overlap, FALSE);
-
-       but = uiDefButR_prop(block, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr, activeprop,
-                            0, 0, i, 0, 0, "");
-       uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
-
-       sub = uiLayoutRow(overlap, FALSE);
-
-       /* retrieve icon and name */
-       icon = list_item_icon_get(C, itemptr, rnaicon, 0);
-       if (icon == ICON_NONE || icon == ICON_DOT)
-               icon = 0;
 
        namebuf = RNA_struct_name_get_alloc(itemptr, NULL, 0, NULL);
        name = (namebuf) ? namebuf : "";
 
-       /* hardcoded types */
-       if (itemptr->type == &RNA_MeshTexturePolyLayer || itemptr->type == &RNA_MeshLoopColorLayer) {
-               uiItemL(sub, name, icon);
-               uiBlockSetEmboss(block, UI_EMBOSSN);
-               uiDefIconButR(block, TOG, 0, ICON_SCENE, 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "active_render",
-                             0, 0, 0, 0, 0, NULL);
-               uiBlockSetEmboss(block, UI_EMBOSS);
+       /* Simplest one! */
+       switch (uilst->layout_type) {
+       case UILST_LAYOUT_GRID:
+               uiItemL(layout, "", icon);
+               break;
+       case UILST_LAYOUT_DEFAULT:
+       case UILST_LAYOUT_COMPACT:
+       default:
+               uiItemL(layout, name, icon);
+               break;
        }
-       else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialTextureSlot)) {
-               uiItemL(sub, name, icon);
-               uiBlockSetEmboss(block, UI_EMBOSS);
-               uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, ptr, "use_textures", i, 0, 0, 0, 0,  NULL);
-       }
-       else if (RNA_struct_is_a(itemptr->type, &RNA_SceneRenderLayer)) {
-               uiItemL(sub, name, icon);
-               uiBlockSetEmboss(block, UI_EMBOSS);
-               uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "use", 0, 0, 0, 0, 0,  NULL);
-       }
-       else if (RNA_struct_is_a(itemptr->type, &RNA_MaterialSlot)) {
-               /* provision to draw active node name */
-               Material *ma, *manode;
-               Scene *scene = CTX_data_scene(C);
-               Object *ob = (Object *)ptr->id.data;
-               int index = (Material **)itemptr->data - ob->mat;
-               
-               /* default item with material base name */
-               uiItemL(sub, name, icon);
-               
-               ma = give_current_material(ob, index + 1);
-               if (ma && !BKE_scene_use_new_shading_nodes(scene)) {
-                       manode = give_node_material(ma);
-                       if (manode) {
-                               char str[MAX_ID_NAME + 12];
-                               BLI_snprintf(str, sizeof(str), IFACE_("Node %s"), manode->id.name + 2);
-                               uiItemL(sub, str, ui_id_icon_get(C, &manode->id, 1));
-                       }
-                       else if (ma->use_nodes) {
-                               uiItemL(sub, IFACE_("Node <none>"), ICON_NONE);
-                       }
-               }
-       }
-       else if (itemptr->type == &RNA_ShapeKey) {
-               Object *ob = (Object *)activeptr->data;
-               Key *key = (Key *)itemptr->id.data;
-               KeyBlock *kb = (KeyBlock *)itemptr->data;
-
-               split = uiLayoutSplit(sub, 0.66f, FALSE);
-
-               uiItemL(split, name, icon);
-
-               uiBlockSetEmboss(block, UI_EMBOSSN);
-               row = uiLayoutRow(split, TRUE);
-               if (i == 0 || (key->type != KEY_RELATIVE)) uiItemL(row, "", ICON_NONE);
-               else uiItemR(row, itemptr, "value", 0, "", ICON_NONE);
-               uiItemR(row, itemptr, "mute", 0, "", ICON_NONE);
-
-               if ((kb->flag & KEYBLOCK_MUTE) ||
-                   (ob->mode == OB_MODE_EDIT && !((ob->shapeflag & OB_SHAPE_EDIT_MODE) && ob->type == OB_MESH)))
-               {
-                       uiLayoutSetActive(row, FALSE);
-               }
-               uiBlockSetEmboss(block, UI_EMBOSS);
-       }
-       else if (itemptr->type == &RNA_VertexGroup) {
-               bDeformGroup *dg = (bDeformGroup *)itemptr->data;
-               uiItemL(sub, name, icon);
-               /* RNA does not allow nice lock icons, use lower level buttons */
-#if 0
-               uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "lock_weight", 0, 0, 0, 0, 0,  NULL);
-#else
-               uiBlockSetEmboss(block, UI_EMBOSSN);
-               uiDefIconButBitC(block, TOG, DG_LOCK_WEIGHT, 0, (dg->flag & DG_LOCK_WEIGHT) ? ICON_LOCKED : ICON_UNLOCKED,
-                                0, 0, UI_UNIT_X, UI_UNIT_Y, &dg->flag, 0, 0, 0, 0,
-                                TIP_("Maintain relative weights while painting"));
-               uiBlockSetEmboss(block, UI_EMBOSS);
-#endif
-       }
-       else if (itemptr->type == &RNA_KeyingSetPath) {
-               KS_Path *ksp = (KS_Path *)itemptr->data;
-               
-               /* icon needs to be the type of ID which is currently active */
-               RNA_enum_icon_from_value(id_type_items, ksp->idtype, &icon);
-               
-               /* nothing else special to do... */
-               uiItemL(sub, name, icon); /* fails, backdrop LISTROW... */
-       }
-       else if (itemptr->type == &RNA_DynamicPaintSurface) {
-               char name_final[96];
-               const char *enum_name;
-               PropertyRNA *prop = RNA_struct_find_property(itemptr, "surface_type");
-               DynamicPaintSurface *surface = (DynamicPaintSurface *)itemptr->data;
-
-               RNA_property_enum_name(C, itemptr, prop, RNA_property_enum_get(itemptr, prop), &enum_name);
-
-               BLI_snprintf(name_final, sizeof(name_final), "%s (%s)", name, enum_name);
-               uiItemL(sub, name_final, icon);
-               if (dynamicPaint_surfaceHasColorPreview(surface)) {
-                       uiBlockSetEmboss(block, UI_EMBOSSN);
-                       uiDefIconButR(block, OPTION, 0,
-                                     (surface->flags & MOD_DPAINT_PREVIEW) ? ICON_RESTRICT_VIEW_OFF : ICON_RESTRICT_VIEW_ON,
-                                     0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "show_preview", 0, 0, 0, 0, 0, NULL);
-                       uiBlockSetEmboss(block, UI_EMBOSS);
-               }
-               uiDefButR(block, OPTION, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, itemptr, "is_active", i, 0, 0, 0, 0,  NULL);
-       }
-       else if (itemptr->type == &RNA_MovieTrackingObject) {
-               MovieTrackingObject *tracking_object = (MovieTrackingObject *)itemptr->data;
-
-               split = uiLayoutSplit(sub, 0.75f, FALSE);
-               if (tracking_object->flag & TRACKING_OBJECT_CAMERA) {
-                       uiItemL(split, name, ICON_CAMERA_DATA);
-               }
-               else {
-                       uiItemL(split, name, ICON_OBJECT_DATA);
-               }
-       }
-       else if (itemptr->type == &RNA_MaskLayer) {
-               split = uiLayoutRow(sub, FALSE);
-
-               uiItemL(split, name, icon);
-
-               uiBlockSetEmboss(block, UI_EMBOSSN);
-               row = uiLayoutRow(split, TRUE);
-               uiItemR(row, itemptr, "alpha", 0, "", ICON_NONE);
-               uiItemR(row, itemptr, "hide", 0, "", ICON_NONE);
-               uiItemR(row, itemptr, "hide_select", 0, "", ICON_NONE);
-               uiItemR(row, itemptr, "hide_render", 0, "", ICON_NONE);
-
-               uiBlockSetEmboss(block, UI_EMBOSS);
-       }
-
-       /* There is a last chance to display custom controls (in addition to the name/label):
-        * If the given item property group features a string property named as prop_list,
-        * this tries to add controls for all properties of the item listed in that string property.
-        * (colon-separated names).
-        *
-        * This is especially useful for python. E.g., if you list a collection of this property
-        * group:
-        *
-        * class TestPropertyGroup(bpy.types.PropertyGroup):
-        *     bool    = BoolProperty(default=False)
-        *     integer = IntProperty()
-        *     string  = StringProperty()
-        * 
-        *     # A string of all identifiers (colon-separated) which property's controls should be
-        *     # displayed in a template_list.
-        *     template_list_controls = StringProperty(default="integer:bool:string", options={"HIDDEN"})
-        *
-        * ... you'll get a numfield for the integer prop, a check box for the bool prop, and a textfield
-        * for the string prop, after the name of each item of the collection.
-        */
-       else if (prop_list_id) {
-               row = uiLayoutRow(sub, TRUE);
-               uiItemL(row, name, icon);
-
-               /* XXX: Check, as sometimes we get an itemptr looking like
-                *      {id = {data = 0x0}, type = 0x0, data = 0x0}
-                *      which would obviously produce a sigsev... */
-               if (itemptr->type) {
-                       /* If the special property is set for the item, and it is a collection... */
-                       PropertyRNA *prop_list = RNA_struct_find_property(itemptr, prop_list_id);
-
-                       if (prop_list && RNA_property_type(prop_list) == PROP_STRING) {
-                               int prop_names_len;
-                               char *prop_names = RNA_property_string_get_alloc(itemptr, prop_list, NULL, 0, &prop_names_len);
-                               char *prop_names_end = prop_names + prop_names_len;
-                               char *id = prop_names;
-                               char *id_next;
-                               while (id < prop_names_end) {
-                                       if ((id_next = strchr(id, ':'))) *id_next++ = '\0';
-                                       else id_next = prop_names_end;
-                                       uiItemR(row, itemptr, id, 0, NULL, ICON_NONE);
-                                       id = id_next;
-                               }
-                               MEM_freeN(prop_names);
-                       }
-               }
-       }
-
-       else
-               uiItemL(sub, name, icon);  /* fails, backdrop LISTROW... */
 
        /* free name */
        if (namebuf) {
@@ -2586,177 +2357,166 @@ static void list_item_row(bContext *C, uiLayout *layout, PointerRNA *ptr, Pointe
        }
 }
 
-void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *activeptr,
-                    const char *activepropname, const char *prop_list, int rows, int maxrows, int listtype)
+void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
+                    PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr,
+                    const char *active_propname, int rows, int maxrows, int layout_type)
 {
+       uiListType *ult;
+       uiList *uilst = NULL;
+       ARegion *ar;
+       uiListDrawItemFunc draw_item;
+
        PropertyRNA *prop = NULL, *activeprop;
        PropertyType type, activetype;
        StructRNA *ptype;
-       uiLayout *box, *row, *col;
-       uiBlock *block;
+       uiLayout *box, *row, *col, *sub, *overlap;
+       uiBlock *block, *subblock;
        uiBut *but;
-       Panel *pa;
-       const char *name;
+
+       char uilst_id[UI_MAX_NAME_STR];
        char numstr[32];
-       int rnaicon = 0, icon = 0, i = 0, activei = 0, len = 0, items, found, min, max;
+       int rnaicon = ICON_NONE, icon = ICON_NONE;
+       int i = 0, activei = 0;
+       int len = 0;
+       int items;
+       int found;
+       int min, max;
 
        /* validate arguments */
        block = uiLayoutGetBlock(layout);
-       pa = block->panel;
 
-       if (!pa) {
-               RNA_warning("Only works inside a panel");
+       if (!active_dataptr->data) {
+               RNA_warning("No active data");
                return;
        }
 
-       if (!activeptr->data)
-               return;
-       
-       if (ptr->data) {
-               prop = RNA_struct_find_property(ptr, propname);
+       if (dataptr->data) {
+               prop = RNA_struct_find_property(dataptr, propname);
                if (!prop) {
-                       RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+                       RNA_warning("Property not found: %s.%s", RNA_struct_identifier(dataptr->type), propname);
                        return;
                }
        }
 
-       activeprop = RNA_struct_find_property(activeptr, activepropname);
+       activeprop = RNA_struct_find_property(active_dataptr, active_propname);
        if (!activeprop) {
-               RNA_warning("Property not found: %s.%s", RNA_struct_identifier(ptr->type), activepropname);
+               RNA_warning("Property not found: %s.%s", RNA_struct_identifier(active_dataptr->type), active_propname);
                return;
        }
 
        if (prop) {
                type = RNA_property_type(prop);
                if (type != PROP_COLLECTION) {
-                       RNA_warning("uiExpected collection property");
+                       RNA_warning("Expected a collection data property");
                        return;
                }
        }
 
        activetype = RNA_property_type(activeprop);
        if (activetype != PROP_INT) {
-               RNA_warning("Expected integer property");
+               RNA_warning("Expected an integer active data property");
                return;
        }
 
        /* get icon */
-       if (ptr->data && prop) {
-               ptype = RNA_property_pointer_type(ptr, prop);
+       if (dataptr->data && prop) {
+               ptype = RNA_property_pointer_type(dataptr, prop);
                rnaicon = RNA_struct_ui_icon(ptype);
        }
 
        /* get active data */
-       activei = RNA_property_int_get(activeptr, activeprop);
+       activei = RNA_property_int_get(active_dataptr, activeprop);
 
-       if (listtype == 'i') {
-               box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
-               col = uiLayoutColumn(box, TRUE);
-               row = uiLayoutRow(col, FALSE);
+       /* Find the uiList type. */
+       ult = WM_uilisttype_find(listtype_name, FALSE);
 
-               if (ptr->data && prop) {
-                       /* create list items */
-                       RNA_PROP_BEGIN (ptr, itemptr, prop)
-                       {
-                               /* create button */
-                               if (!(i % 9))
-                                       row = uiLayoutRow(col, FALSE);
-
-                               icon = list_item_icon_get(C, &itemptr, rnaicon, 1);
-                               but = uiDefIconButR_prop(block, LISTROW, 0, icon, 0, 0, UI_UNIT_X * 10, UI_UNIT_Y, activeptr,
-                                                        activeprop, 0, 0, i, 0, 0, "");
-                               uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
-                               
-
-                               i++;
-                       }
-                       RNA_PROP_END;
-               }
+       if (ult == NULL) {
+               RNA_warning("List type %s not found", listtype_name);
+               return;
        }
-       else if (listtype == 'c') {
-               /* compact layout */
-
-               row = uiLayoutRow(layout, TRUE);
 
-               if (ptr->data && prop) {
-                       /* create list items */
-                       RNA_PROP_BEGIN (ptr, itemptr, prop)
-                       {
-                               found = (activei == i);
+       draw_item = ult->draw_item ? ult->draw_item : uilist_draw_item_default;
 
-                               if (found) {
-                                       /* create button */
-                                       name = RNA_struct_name_get_alloc(&itemptr, NULL, 0, NULL);
-                                       icon = list_item_icon_get(C, &itemptr, rnaicon, 0);
-                                       uiItemL(row, (name) ? name : "", icon);
+       /* Find or add the uiList to the current Region. */
+       /* We tag the list id with the list type... */
+       BLI_snprintf(uilst_id, sizeof(uilst_id), "%s_%s", ult->idname, list_id ? list_id : "");
 
-                                       if (name) {
-                                               MEM_freeN((void *)name);
-                                       }
-                               }
+       ar = CTX_wm_region(C);
+       uilst = BLI_findstring(&ar->uiLists, uilst_id, offsetof(uiList, list_id));
 
-                               i++;
-                       }
-                       RNA_PROP_END;
-               }
+       if (!uilst) {
+               uilst = MEM_callocN(sizeof(uiList), __func__);
+               BLI_strncpy(uilst->list_id, uilst_id, sizeof(uilst->list_id));
+               BLI_addtail(&ar->uiLists, uilst);
+       }
 
-               /* if not found, add in dummy button */
-               if (i == 0)
-                       uiItemL(row, "", ICON_NONE);
+       /* Because we can't actually pass type across save&load... */
+       uilst->type = ult;
+       uilst->layout_type = layout_type;
 
-               /* next/prev button */
-               BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
-               but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y, activeptr,
-                                            activeprop, 0, 0, 0, 0, 0, "");
-               if (i == 0)
-                       uiButSetFlag(but, UI_BUT_DISABLED);
-       }
-       else {
+       switch (layout_type) {
+       case UILST_LAYOUT_DEFAULT:
                /* default rows */
                if (rows == 0)
                        rows = 5;
                if (maxrows == 0)
                        maxrows = 5;
-               if (pa->list_grip_size != 0)
-                       rows = pa->list_grip_size;
+               if (uilst->list_grip_size != 0)
+                       rows = uilst->list_grip_size;
 
                /* layout */
-               box = uiLayoutListBox(layout, ptr, prop, activeptr, activeprop);
+               box = uiLayoutListBox(layout, uilst, dataptr, prop, active_dataptr, activeprop);
                row = uiLayoutRow(box, FALSE);
                col = uiLayoutColumn(row, TRUE);
 
                /* init numbers */
-               RNA_property_int_range(activeptr, activeprop, &min, &max);
+               RNA_property_int_range(active_dataptr, activeprop, &min, &max);
 
                if (prop)
-                       len = RNA_property_collection_length(ptr, prop);
+                       len = RNA_property_collection_length(dataptr, prop);
                items = CLAMPIS(len, rows, MAX2(rows, maxrows));
 
                /* if list length changes and active is out of view, scroll to it */
-               if (pa->list_last_len != len)
-                       if ((activei < pa->list_scroll || activei >= pa->list_scroll + items))
-                               pa->list_scroll = activei;
+               if ((uilst->list_last_len != len) &&
+                   (activei < uilst->list_scroll || activei >= uilst->list_scroll + items)) {
+                       uilst->list_scroll = activei;
+               }
 
-               pa->list_scroll = MIN2(pa->list_scroll, len - items);
-               pa->list_scroll = MAX2(pa->list_scroll, 0);
-               pa->list_size = items;
-               pa->list_last_len = len;
+               uilst->list_scroll = MIN2(uilst->list_scroll, len - items);
+               uilst->list_scroll = MAX2(uilst->list_scroll, 0);
+               uilst->list_size = items;
+               uilst->list_last_len = len;
 
-               if (ptr->data && prop) {
+               if (dataptr->data && prop) {
                        /* create list items */
-                       RNA_PROP_BEGIN (ptr, itemptr, prop)
+                       RNA_PROP_BEGIN (dataptr, itemptr, prop)
                        {
-                               if (i >= pa->list_scroll && i < pa->list_scroll + items)
-                                       list_item_row(C, col, ptr, &itemptr, i, rnaicon, activeptr, activeprop, prop_list);
+                               if (i >= uilst->list_scroll && i < uilst->list_scroll + items) {
+                                       subblock = uiLayoutGetBlock(col);
+                                       overlap = uiLayoutOverlap(col);
+
+                                       /* list item behind label & other buttons */
+                                       sub = uiLayoutRow(overlap, FALSE);
+
+                                       but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+                                                            active_dataptr, activeprop, 0, 0, i, 0, 0, "");
+                                       uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
+
+                                       sub = uiLayoutRow(overlap, FALSE);
 
+                                       icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE);
+                                       if (icon == ICON_DOT)
+                                               icon = ICON_NONE;
+                                       draw_item(uilst, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
+                               }
                                i++;
                        }
                        RNA_PROP_END;
                }
 
                /* add dummy buttons to fill space */
-               while (i < pa->list_scroll + items) {
-                       if (i >= pa->list_scroll)
+               while (i < uilst->list_scroll + items) {
+                       if (i >= uilst->list_scroll)
                                uiItemL(col, "", ICON_NONE);
                        i++;
                }
@@ -2764,9 +2524,75 @@ void uiTemplateList(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *
                /* add scrollbar */
                if (len > items) {
                        col = uiLayoutColumn(row, FALSE);
-                       uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &pa->list_scroll,
+                       uiDefButI(block, SCROLL, 0, "", 0, 0, UI_UNIT_X * 0.75, UI_UNIT_Y * items, &uilst->list_scroll,
                                  0, len - items, items, 0, "");
                }
+               break;
+       case UILST_LAYOUT_COMPACT:
+               row = uiLayoutRow(layout, TRUE);
+
+               if (dataptr->data && prop) {
+                       /* create list items */
+                       RNA_PROP_BEGIN (dataptr, itemptr, prop)
+                       {
+                               found = (activei == i);
+
+                               if (found) {
+                                       icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE);
+                                       if (icon == ICON_DOT)
+                                               icon = ICON_NONE;
+                                       draw_item(uilst, C, row, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
+                               }
+
+                               i++;
+                       }
+                       RNA_PROP_END;
+               }
+
+               /* if list is empty, add in dummy button */
+               if (i == 0)
+                       uiItemL(row, "", ICON_NONE);
+
+               /* next/prev button */
+               BLI_snprintf(numstr, sizeof(numstr), "%d :", i);
+               but = uiDefIconTextButR_prop(block, NUM, 0, 0, numstr, 0, 0, UI_UNIT_X * 5, UI_UNIT_Y,
+                                            active_dataptr, activeprop, 0, 0, 0, 0, 0, "");
+               if (i == 0)
+                       uiButSetFlag(but, UI_BUT_DISABLED);
+               break;
+       case UILST_LAYOUT_GRID:
+               box = uiLayoutListBox(layout, uilst, dataptr, prop, active_dataptr, activeprop);
+               col = uiLayoutColumn(box, TRUE);
+               row = uiLayoutRow(col, FALSE);
+
+               if (dataptr->data && prop) {
+                       /* create list items */
+                       RNA_PROP_BEGIN (dataptr, itemptr, prop)
+                       {
+                               /* create button */
+                               if (!(i % 9))
+                                       row = uiLayoutRow(col, FALSE);
+
+                               subblock = uiLayoutGetBlock(row);
+                               overlap = uiLayoutOverlap(row);
+
+                               /* list item behind label & other buttons */
+                               sub = uiLayoutRow(overlap, FALSE);
+
+                               but = uiDefButR_prop(subblock, LISTROW, 0, "", 0, 0, UI_UNIT_X * 10, UI_UNIT_Y,
+                                                    active_dataptr, activeprop, 0, 0, i, 0, 0, "");
+                               uiButSetFlag(but, UI_BUT_NO_TOOLTIP);
+
+                               sub = uiLayoutRow(overlap, FALSE);
+
+                               icon = UI_rnaptr_icon_get(C, &itemptr, rnaicon, FALSE);
+                               draw_item(uilst, C, sub, dataptr, &itemptr, icon, active_dataptr, active_propname, i);
+
+                               i++;
+                       }
+                       RNA_PROP_END;
+               }
+               break;
        }
 }
 
index 59dd66a02078946dc424e7ed548033e14c36afda..b702dc4c0bc0ba21deddf82664df53528252afcc 100644 (file)
@@ -2152,12 +2152,12 @@ static void node_composit_buts_file_output_details(uiLayout *layout, bContext *C
        active_index = RNA_int_get(ptr, "active_input_index");
        /* using different collection properties if multilayer format is enabled */
        if (multilayer) {
-               uiTemplateList(col, C, ptr, "layer_slots", ptr, "active_input_index", NULL, 0, 0, 0);
+               uiTemplateList(col, C, "UI_UL_list", "", ptr, "layer_slots", ptr, "active_input_index", 0, 0, 0);
                RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "layer_slots"),
                                                   active_index, &active_input_ptr);
        }
        else {
-               uiTemplateList(col, C, ptr, "file_slots", ptr, "active_input_index", NULL, 0, 0, 0);
+               uiTemplateList(col, C, "UI_UL_list", "", ptr, "file_slots", ptr, "active_input_index", 0, 0, 0);
                RNA_property_collection_lookup_int(ptr, RNA_struct_find_property(ptr, "file_slots"),
                                                   active_index, &active_input_ptr);
        }
index de6ddb4b8966f4edc39065a8e4cb7f41331c3799..5d8176c802176dfef35f6077097de4593652991e 100644 (file)
@@ -110,12 +110,26 @@ typedef struct Panel {            /* the part from uiBlock that needs saved in file */
        int sortorder;                  /* panels are aligned according to increasing sortorder */
        struct Panel *paneltab;         /* this panel is tabbed in *paneltab */
        void *activedata;                       /* runtime for panel manipulation */
-
-       int list_scroll, list_size;
-       int list_last_len, list_grip_size;
-       char list_search[64];
 } Panel;
 
+typedef struct uiList {                                /* some list UI data need to be saved in file */
+       struct uiList *next, *prev;
+
+       struct uiListType *type;                /* runtime */
+       void *padp;
+
+       char list_id[64];                               /* defined as UI_MAX_NAME_STR */
+
+       int layout_type;                                /* How items are layedout in the list */
+       int padi;
+
+       int list_scroll;
+       int list_size;
+       int list_last_len;
+       int list_grip_size;
+/*     char list_search[64]; */
+} uiList;
+
 typedef struct ScrArea {
        struct ScrArea *next, *prev;
        
@@ -167,6 +181,7 @@ typedef struct ARegion {
        
        ListBase uiblocks;                      /* uiBlock */
        ListBase panels;                        /* Panel */
+       ListBase uiLists;                       /* uiList */
        ListBase handlers;                      /* wmEventHandler */
        
        struct wmTimer *regiontimer; /* blend in/out */
@@ -216,6 +231,13 @@ typedef struct ARegion {
 #define PNL_DEFAULT_CLOSED             1
 #define PNL_NO_HEADER                  2
 
+/* uilist layout_type */
+enum {
+       UILST_LAYOUT_DEFAULT          = 0,
+       UILST_LAYOUT_COMPACT          = 1,
+       UILST_LAYOUT_GRID             = 2,
+};
+
 /* regiontype, first two are the default set */
 /* Do NOT change order, append on end. Types are hardcoded needed */
 enum {
index 7625605c5fbba45e38677c99e5b58ba69ece4716..bf78c622cbdb3791df51fc3d51f8efaeada3a047 100644 (file)
@@ -587,7 +587,7 @@ extern StructRNA RNA_TrackToConstraint;
 extern StructRNA RNA_TransformConstraint;
 extern StructRNA RNA_TransformSequence;
 extern StructRNA RNA_UILayout;
-extern StructRNA RNA_UIListItem;
+extern StructRNA RNA_UIList;
 extern StructRNA RNA_UVWarpModifier;
 extern StructRNA RNA_UVProjectModifier;
 extern StructRNA RNA_UVProjector;
index 9d08cf2d3646b3135e38972c51e39ec48394579b..49f881ce2853ca99c34a75a69f8a0c0f9abd24f2 100644 (file)
@@ -133,6 +133,9 @@ extern EnumPropertyItem prop_dynamicpaint_type_items[];
 
 extern EnumPropertyItem clip_editor_mode_items[];
 
+extern EnumPropertyItem icon_items[];
+extern EnumPropertyItem uilist_layout_type_items[];
+
 struct bContext;
 struct PointerRNA;
 struct PropertyRNA;
index 4f9f2009a142fa3e4c417b4e6053211ba671ab94..030325494ff45d0e8763bb9f58e999c2d85c121f 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "rna_internal.h"
 
+#include "BLI_math_base.h"
+
 #include "BKE_modifier.h"
 #include "BKE_dynamicpaint.h"
 
@@ -219,6 +221,14 @@ static int rna_DynamicPaint_is_cache_user_get(PointerRNA *ptr)
        return (surface->format != MOD_DPAINT_SURFACE_F_IMAGESEQ) ?  1 : 0;
 }
 
+/* is some 3D view preview available */
+static int rna_DynamicPaint_use_color_preview_get(PointerRNA *ptr)
+{
+       DynamicPaintSurface *surface = (DynamicPaintSurface *)ptr->data;
+
+       return dynamicPaint_surfaceHasColorPreview(surface);
+}
+
 /* does output layer exist*/
 static int rna_DynamicPaint_is_output_exists(DynamicPaintSurface *surface, Object *ob, int index)
 {
@@ -239,6 +249,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
        tmp.value = MOD_DPAINT_SURFACE_T_PAINT;
        tmp.identifier = "PAINT";
        tmp.name = "Paint";
+       tmp.icon = ICON_TPAINT_HLT;
        RNA_enum_item_add(&item, &totitem, &tmp);
 
        /* Displace */
@@ -248,6 +259,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
                tmp.value = MOD_DPAINT_SURFACE_T_DISPLACE;
                tmp.identifier = "DISPLACE";
                tmp.name = "Displace";
+               tmp.icon = ICON_MOD_DISPLACE;
                RNA_enum_item_add(&item, &totitem, &tmp);
        }
 
@@ -256,6 +268,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
                tmp.value = MOD_DPAINT_SURFACE_T_WEIGHT;
                tmp.identifier = "WEIGHT";
                tmp.name = "Weight";
+               tmp.icon = ICON_MOD_VERTEX_WEIGHT;
                RNA_enum_item_add(&item, &totitem, &tmp);
        }
 
@@ -264,6 +277,7 @@ static EnumPropertyItem *rna_DynamicPaint_surface_type_itemf(bContext *C, Pointe
                tmp.value = MOD_DPAINT_SURFACE_T_WAVE;
                tmp.identifier = "WAVE";
                tmp.name = "Waves";
+               tmp.icon = ICON_MOD_WAVE;
                RNA_enum_item_add(&item, &totitem, &tmp);
        }
 
@@ -705,6 +719,14 @@ static void rna_def_canvas_surface(BlenderRNA *brna)
        RNA_def_property_boolean_funcs(prop, "rna_DynamicPaint_is_cache_user_get", NULL);
        RNA_def_property_ui_text(prop, "Use Cache", "");
        RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+
+       /* whether this surface has preview data for 3D view */
+       RNA_define_verify_sdna(FALSE);
+       prop = RNA_def_property(srna, "use_color_preview", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_funcs(prop, "rna_DynamicPaint_use_color_preview_get", NULL);
+       RNA_def_property_ui_text(prop, "Use Corlor Preview", "Whether this surface has some color preview for 3D view");
+       RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE);
+       RNA_define_verify_sdna(TRUE);
 }
 
 static void rna_def_dynamic_paint_canvas_settings(BlenderRNA *brna)
index de359fd641390c340370ace264c5dec50d6b9162..e6e953c412b901b4c94344285109e46666410901 100644 (file)
@@ -55,6 +55,16 @@ EnumPropertyItem operator_context_items[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
+EnumPropertyItem uilist_layout_type_items[] = {
+       {UILST_LAYOUT_DEFAULT, "DEFAULT", 0, "Default Layout",
+                              "Use the default, multi-rows layout"},
+       {UILST_LAYOUT_COMPACT, "COMPACT", 0, "Compact Layout",
+                              "Use the compact, single-row layout"},
+       {UILST_LAYOUT_GRID, "GRID", 0, "Grid Layout",
+                           "Use the grid-based layout"},
+       {0, NULL, 0, NULL, NULL}
+};
+
 #ifdef RNA_RUNTIME
 
 #include <assert.h>
@@ -252,6 +262,105 @@ static StructRNA *rna_Panel_refine(PointerRNA *ptr)
        return (hdr->type && hdr->type->ext.srna) ? hdr->type->ext.srna : &RNA_Panel;
 }
 
+/* UIList */
+static void uilist_draw_item(uiList *uilst, bContext *C, uiLayout *layout, PointerRNA *dataptr, PointerRNA *itemptr,
+                             int icon, PointerRNA *active_dataptr, const char *active_propname, int index)
+{
+       extern FunctionRNA rna_UIList_draw_item_func;
+
+       PointerRNA ultr;
+       ParameterList list;
+       FunctionRNA *func;
+
+       RNA_pointer_create(&CTX_wm_screen(C)->id, uilst->type->ext.srna, uilst, &ultr);
+       func = &rna_UIList_draw_item_func; /* RNA_struct_find_function(&ultr, "draw_item"); */
+
+       RNA_parameter_list_create(&list, &ultr, func);
+       RNA_parameter_set_lookup(&list, "context", &C);
+       RNA_parameter_set_lookup(&list, "layout", &layout);
+       RNA_parameter_set_lookup(&list, "data", dataptr);
+       RNA_parameter_set_lookup(&list, "item", itemptr);
+       RNA_parameter_set_lookup(&list, "icon", &icon);
+       RNA_parameter_set_lookup(&list, "active_data", active_dataptr);
+       RNA_parameter_set_lookup(&list, "active_property", &active_propname);
+       RNA_parameter_set_lookup(&list, "index", &index);
+       uilst->type->ext.call((bContext *)C, &ultr, func, &list);
+
+       RNA_parameter_list_free(&list);
+}
+
+static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type)
+{
+       uiListType *ult = RNA_struct_blender_type_get(type);
+
+       if (!ult)
+               return;
+
+       RNA_struct_free_extension(type, &ult->ext);
+
+       WM_uilisttype_freelink(ult);
+
+       RNA_struct_free(&BLENDER_RNA, type);
+
+       /* update while blender is running */
+       WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+}
+
+static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
+                                      StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+       uiListType *ult, dummyult = {NULL};
+       uiList dummyuilist = {NULL};
+       PointerRNA dummyultr;
+       int have_function[1];
+       size_t over_alloc = 0; /* warning, if this becomes a bess, we better do another alloc */
+
+       /* setup dummy menu & menu type to store static properties in */
+       dummyuilist.type = &dummyult;
+       RNA_pointer_create(NULL, &RNA_UIList, &dummyuilist, &dummyultr);
+
+       /* validate the python class */
+       if (validate(&dummyultr, data, have_function) != 0)
+               return NULL;
+
+       if (strlen(identifier) >= sizeof(dummyult.idname)) {
+               BKE_reportf(reports, RPT_ERROR, "Registering uilist class: '%s' is too long, maximum length is %d",
+                           identifier, (int)sizeof(dummyult.idname));
+               return NULL;
+       }
+
+       /* check if we have registered this uilist type before, and remove it */
+       ult = WM_uilisttype_find(dummyult.idname, TRUE);
+       if (ult && ult->ext.srna)
+               rna_UIList_unregister(bmain, ult->ext.srna);
+
+       /* create a new menu type */
+       ult = MEM_callocN(sizeof(uiListType) + over_alloc, "python uilist");
+       memcpy(ult, &dummyult, sizeof(dummyult));
+
+       ult->ext.srna = RNA_def_struct(&BLENDER_RNA, ult->idname, "UIList");
+       ult->ext.data = data;
+       ult->ext.call = call;
+       ult->ext.free = free;
+       RNA_struct_blender_type_set(ult->ext.srna, ult);
+       RNA_def_struct_flag(ult->ext.srna, STRUCT_NO_IDPROPERTIES);
+
+       ult->draw_item = (have_function[0]) ? uilist_draw_item : NULL;
+
+       WM_uilisttype_add(ult);
+
+       /* update while blender is running */
+       WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL);
+
+       return ult->ext.srna;
+}
+
+static StructRNA *rna_UIList_refine(PointerRNA *ptr)
+{
+       uiList *uilst = (uiList *)ptr->data;
+       return (uilst->type && uilst->type->ext.srna) ? uilst->type->ext.srna : &RNA_UIList;
+}
+
 /* Header */
 
 static void header_draw(const bContext *C, Header *hdr)
@@ -495,6 +604,8 @@ static void rna_Menu_bl_description_set(PointerRNA *ptr, const char *value)
        else assert(!"setting the bl_description on a non-builtin menu");
 }
 
+/* UILayout */
+
 static int rna_UILayout_active_get(PointerRNA *ptr)
 {
        return uiLayoutGetActive(ptr->data);
@@ -738,6 +849,58 @@ static void rna_def_panel(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Options",  "Options for this panel type");
 }
 
+static void rna_def_uilist(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+       PropertyRNA *parm;
+       FunctionRNA *func;
+
+       srna = RNA_def_struct(brna, "UIList", NULL);
+       RNA_def_struct_ui_text(srna, "UIList", "UI list containing the elements of a collection");
+       RNA_def_struct_sdna(srna, "uiList");
+       RNA_def_struct_refine_func(srna, "rna_UIList_refine");
+       RNA_def_struct_register_funcs(srna, "rna_UIList_register", "rna_UIList_unregister", NULL);
+
+       /* draw */
+       func = RNA_def_function(srna, "draw_item", NULL);
+       RNA_def_function_ui_description(func, "Draw an item in the list (NOTE: when you define your own draw_item "
+                                             "function, you may want to check given 'item' is of the right type...)");
+       RNA_def_function_flag(func, FUNC_REGISTER);
+       parm = RNA_def_pointer(func, "context", "Context", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item");
+       RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
+       parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property");
+       RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+       parm = RNA_def_pointer(func, "item", "AnyType", "", "Item of the collection property");
+       RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
+       parm = RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Icon of the item in the collection", 0, INT_MAX);
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm = RNA_def_pointer(func, "active_data", "AnyType", "",
+                              "Data from which to take property for the active element");
+       RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+       parm = RNA_def_string(func, "active_property", "", 0, "",
+                             "Identifier of property in active_data, for the active element");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX);
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+
+       prop = RNA_def_property(srna, "layout_type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, uilist_layout_type_items);
+       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+       /* registration */
+       prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "type->idname");
+       RNA_def_property_flag(prop, PROP_REGISTER | PROP_NEVER_CLAMP);
+       RNA_def_property_ui_text(prop, "ID Name",
+                                "If this is set, the uilist gets a custom ID, otherwise it takes the "
+                                "name of the class used to define the uilist (for example, if the "
+                                "class name is \"OBJECT_UL_vgroups\", and bl_idname is not set by the "
+                                "script, then bl_idname = \"OBJECT_UL_vgroups\")");
+}
+
 static void rna_def_header(BlenderRNA *brna)
 {
        StructRNA *srna;
@@ -852,6 +1015,7 @@ void RNA_def_ui(BlenderRNA *brna)
 {
        rna_def_ui_layout(brna);
        rna_def_panel(brna);
+       rna_def_uilist(brna);
        rna_def_header(brna);
        rna_def_menu(brna);
 }
index 548539e3395e55e686fa6842724473528453ce85..366d0dc1fd9d15b016ea7cc19022554da45c977a 100644 (file)
 #include <stdio.h>
 
 #include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "DNA_screen_types.h"
 
 #include "UI_resources.h"
+#include "UI_interface_icons.h"
 
 #include "rna_internal.h"
 
@@ -70,12 +74,117 @@ static PointerRNA rna_uiItemO(uiLayout *layout, const char *opname, const char *
        return uiItemFullO(layout, opname, name, icon, NULL, uiLayoutGetOperatorContext(layout), flag);
 }
 
+static void rna_uiItemL(uiLayout *layout, const char *name, int icon, int icon_value)
+{
+       if (icon_value && !icon) {
+               icon = icon_value;
+       }
+
+       uiItemL(layout, name, icon);
+}
+
+static int rna_ui_get_rnaptr_icon(bContext *C, PointerRNA *ptr_icon)
+{
+       return UI_rnaptr_icon_get(C, ptr_icon, RNA_struct_ui_icon(ptr_icon->type), FALSE);
+}
+
+static const char *rna_ui_get_enum_name(bContext *C, PointerRNA *ptr, const char *propname, const char *identifier)
+{
+       PropertyRNA *prop = NULL;
+       EnumPropertyItem *items = NULL, *item;
+       int free;
+       const char *name = "";
+
+       prop = RNA_struct_find_property(ptr, propname);
+       if (!prop || (RNA_property_type(prop) != PROP_ENUM)) {
+               RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+               return name;
+       }
+
+       RNA_property_enum_items_gettexted(C, ptr, prop, &items, NULL, &free);
+
+       if (items) {
+               for (item = items; item->identifier; item++) {
+                       if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+                               name = item->name;
+                               break;
+                       }
+               }
+               if (free) {
+                       MEM_freeN(items);
+               }
+       }
+
+       return name;
+}
+
+static const char *rna_ui_get_enum_description(bContext *C, PointerRNA *ptr, const char *propname,
+                                               const char *identifier)
+{
+       PropertyRNA *prop = NULL;
+       EnumPropertyItem *items = NULL, *item;
+       int free;
+       const char *desc = "";
+
+       prop = RNA_struct_find_property(ptr, propname);
+       if (!prop || (RNA_property_type(prop) != PROP_ENUM)) {
+               RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+               return desc;
+       }
+
+       RNA_property_enum_items_gettexted(C, ptr, prop, &items, NULL, &free);
+
+       if (items) {
+               for (item = items; item->identifier; item++) {
+                       if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+                               desc = item->description;
+                               break;
+                       }
+               }
+               if (free) {
+                       MEM_freeN(items);
+               }
+       }
+
+       return desc;
+}
+
+static int rna_ui_get_enum_icon(bContext *C, PointerRNA *ptr, const char *propname, const char *identifier)
+{
+       PropertyRNA *prop = NULL;
+       EnumPropertyItem *items = NULL, *item;
+       int free;
+       int icon = ICON_NONE;
+
+       prop = RNA_struct_find_property(ptr, propname);
+       if (!prop || (RNA_property_type(prop) != PROP_ENUM)) {
+               RNA_warning("Property not found or not an enum: %s.%s", RNA_struct_identifier(ptr->type), propname);
+               return icon;
+       }
+
+       RNA_property_enum_items(C, ptr, prop, &items, NULL, &free);
+
+       if (items) {
+               for (item = items; item->identifier; item++) {
+                       if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+                               icon = item->icon;
+                               break;
+                       }
+               }
+               if (free) {
+                       MEM_freeN(items);
+               }
+       }
+
+       return icon;
+}
+
 #else
 
 #define DEF_ICON_BLANK_SKIP
 #define DEF_ICON(name) {ICON_##name, (#name), 0, (#name), ""},
 #define DEF_VICO(name) {VICO_##name, (#name), 0, (#name), ""},
-static EnumPropertyItem icon_items[] = {
+EnumPropertyItem icon_items[] = {
 #include "UI_icons.h"
        {0, NULL, 0, NULL, NULL}
 };
@@ -92,7 +201,6 @@ static void api_ui_item_common(FunctionRNA *func)
        prop = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_items(prop, icon_items);
        RNA_def_property_ui_text(prop, "Icon", "Override automatic icon of the item");
-
 }
 
 static void api_ui_item_op(FunctionRNA *func)
@@ -130,13 +238,6 @@ void RNA_api_ui_layout(StructRNA *srna)
                {'h', "HUE", 0, "Hue", ""},
                {0, NULL, 0, NULL, NULL}
        };
-       
-       static EnumPropertyItem list_type_items[] = {
-               {0, "DEFAULT", 0, "None", ""},
-               {'c', "COMPACT", 0, "Compact", ""},
-               {'i', "ICONS", 0, "Icons", ""},
-               {0, NULL, 0, NULL, NULL}
-       };
 
        /* simple layout specifiers */
        func = RNA_def_function(srna, "row", "uiLayoutRow");
@@ -175,6 +276,44 @@ void RNA_api_ui_layout(StructRNA *srna)
        RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f);
        RNA_def_boolean(func, "align", 0, "", "Align buttons to each other");
 
+       /* Icon of a rna pointer */
+       func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon");
+       parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX);
+       RNA_def_function_return(func, parm);
+       RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+       parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take the icon");
+       RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+       RNA_def_function_ui_description(func, "Return the custom icon for this data, "
+                                             "use it e.g. to get materials or texture icons");
+
+       /* UI name, description and icon of an enum item */
+       func = RNA_def_function(srna, "enum_item_name", "rna_ui_get_enum_name");
+       parm = RNA_def_string(func, "name", "", 0, "", "UI name of the enum item");
+       RNA_def_function_return(func, parm);
+       RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+       api_ui_item_rna_common(func);
+       parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_function_ui_description(func, "Return the UI name for this enum item");
+
+       func = RNA_def_function(srna, "enum_item_description", "rna_ui_get_enum_description");
+       parm = RNA_def_string(func, "description", "", 0, "", "UI description of the enum item");
+       RNA_def_function_return(func, parm);
+       RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+       api_ui_item_rna_common(func);
+       parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_function_ui_description(func, "Return the UI description for this enum item");
+
+       func = RNA_def_function(srna, "enum_item_icon", "rna_ui_get_enum_icon");
+       parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX);
+       RNA_def_function_return(func, parm);
+       RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+       api_ui_item_rna_common(func);
+       parm = RNA_def_string(func, "identifier", "", 0, "", "Identifier of the enum item");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       RNA_def_function_ui_description(func, "Return the icon for this enum item");
+
        /* items */
        func = RNA_def_function(srna, "prop", "rna_uiItemR");
        RNA_def_function_ui_description(func, "Item. Exposes an RNA item and places it into the layout");
@@ -274,9 +413,13 @@ void RNA_api_ui_layout(StructRNA *srna)
        RNA_def_property_flag(parm, PROP_REQUIRED);
 #endif
 
-       func = RNA_def_function(srna, "label", "uiItemL");
-       RNA_def_function_ui_description(func, "Item. Display text in the layout");
+       func = RNA_def_function(srna, "label", "rna_uiItemL");
+       RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout");
        api_ui_item_common(func);
+       parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
+       RNA_def_property_ui_text(parm, "Icon Value",
+                                "Override automatic icon of the item "
+                                "(use it e.g. with custom material icons returned by icon()...)");
 
        func = RNA_def_function(srna, "menu", "uiItemM");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -439,26 +582,29 @@ void RNA_api_ui_layout(StructRNA *srna)
        RNA_def_boolean(func, "compact", 0, "", "Use more compact layout");
 
        func = RNA_def_function(srna, "template_list", "uiTemplateList");
-       RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups "
-                                             "(WARNING: only one per panel allowed!).");
+       RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups.");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
-       parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
+       parm = RNA_def_string(func, "listtype_name", "", 0, "", "Identifier of the list type to use");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm = RNA_def_string(func, "list_id", "", 0, "",
+                             "Identifier of this list widget. "
+                             "If this is set, the uilist gets a custom ID, otherwise it takes the "
+                             "name of the class used to define the uilist (for example, if the "
+                             "class name is \"OBJECT_UL_vgroups\", and list_id is not set by the "
+                             "script, then bl_idname = \"OBJECT_UL_vgroups\")");
+       parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property");
        RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR);
-       parm = RNA_def_string(func, "property", "", 0, "", "Identifier of property in data");
+       parm = RNA_def_string(func, "propname", "", 0, "", "Identifier of the Collection property in data");
        RNA_def_property_flag(parm, PROP_REQUIRED);
-       parm = RNA_def_pointer(func, "active_data", "AnyType", "",
-                              "Data from which to take property for the active element");
+       parm = RNA_def_pointer(func, "active_dataptr", "AnyType", "",
+                              "Data from which to take the integer property, index of the active item");
        RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
-       parm = RNA_def_string(func, "active_property", "", 0, "",
-                             "Identifier of property in data, for the active element");
+       parm = RNA_def_string(func, "active_propname", "", 0, "",
+                             "Identifier of the integer property in active_data, index of the active item");
        RNA_def_property_flag(parm, PROP_REQUIRED);
-       RNA_def_string(func, "prop_list", "", 0, "",
-                      "Identifier of a string property in each data member, specifying which "
-                      "of its properties should have a widget displayed in its row "
-                      "(format: \"propname1:propname2:propname3:...\")");
        RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Number of rows to display", 0, INT_MAX);
        RNA_def_int(func, "maxrows", 5, 0, INT_MAX, "", "Maximum number of rows to display", 0, INT_MAX);
-       RNA_def_enum(func, "type", list_type_items, 0, "Type", "Type of list to use");
+       RNA_def_enum(func, "type", uilist_layout_type_items, UILST_LAYOUT_DEFAULT, "Type", "Type of layout to use");
 
        func = RNA_def_function(srna, "template_running_jobs", "uiTemplateRunningJobs");
        RNA_def_function_flag(func, FUNC_USE_CONTEXT);
index 2de477c46c3f7f6c4c20529da847fc6f5ad7e046..bc245ecda5c5bfabc0f4ea6a25a86c16edff6441 100644 (file)
@@ -7373,8 +7373,9 @@ PyDoc_STRVAR(pyrna_register_class_doc,
 ".. method:: register_class(cls)\n"
 "\n"
 "   Register a subclass of a blender type in (:class:`bpy.types.Panel`,\n"
-"   :class:`bpy.types.Menu`, :class:`bpy.types.Header`, :class:`bpy.types.Operator`,\n"
-"   :class:`bpy.types.KeyingSetInfo`, :class:`bpy.types.RenderEngine`).\n"
+"   :class:`bpy.types.UIList`, :class:`bpy.types.Menu`, :class:`bpy.types.Header`,\n"
+"   :class:`bpy.types.Operator`, :class:`bpy.types.KeyingSetInfo`,\n"
+"   :class:`bpy.types.RenderEngine`).\n"
 "\n"
 "   If the class has a *register* class method it will be called\n"
 "   before registration.\n"
index c418b07401d225129c3336ed1d178faeb0cac94e..eee4b5a3a57e422b2c00a947025b5b7b49d15245 100644 (file)
@@ -265,6 +265,13 @@ char               *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struc
 void           WM_operator_bl_idname(char *to, const char *from);
 void           WM_operator_py_idname(char *to, const char *from);
 
+/* *************** uilist types ******************** */
+void                WM_uilisttype_init(void);
+struct uiListType  *WM_uilisttype_find(const char *idname, int quiet);
+int                 WM_uilisttype_add(struct uiListType *ult);
+void                WM_uilisttype_freelink(struct uiListType *ult);
+void                WM_uilisttype_free(void);
+
 /* *************** menu types ******************** */
 void                WM_menutype_init(void);
 struct MenuType    *WM_menutype_find(const char *idname, int quiet);
index 8fe387765ce0e3634d523f4e96f9175f290af839..53e67e91bd26a86c6f15d276d427bc926cc820c7 100644 (file)
@@ -149,7 +149,63 @@ void WM_operator_stack_clear(wmWindowManager *wm)
        WM_main_add_notifier(NC_WM | ND_HISTORY, NULL);
 }
 
-/* ****************************************** */
+
+/* ************ uiListType handling ************** */
+
+static GHash *uilisttypes_hash = NULL;
+
+uiListType *WM_uilisttype_find(const char *idname, int quiet)
+{
+       uiListType *ult;
+
+       if (idname[0]) {
+               ult = BLI_ghash_lookup(uilisttypes_hash, idname);
+               if (ult) {
+                       return ult;
+               }
+       }
+
+       if (!quiet) {
+               printf("search for unknown uilisttype %s\n", idname);
+       }
+
+       return NULL;
+}
+
+int WM_uilisttype_add(uiListType *ult)
+{
+       BLI_ghash_insert(uilisttypes_hash, (void *)ult->idname, ult);
+       return 1;
+}
+
+void WM_uilisttype_freelink(uiListType *ult)
+{
+       BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, (GHashValFreeFP)MEM_freeN);
+}
+
+/* called on initialize WM_init() */
+void WM_uilisttype_init(void)
+{
+       uilisttypes_hash = BLI_ghash_str_new("uilisttypes_hash gh");
+}
+
+void WM_uilisttype_free(void)
+{
+       GHashIterator *iter = BLI_ghashIterator_new(uilisttypes_hash);
+
+       for (; !BLI_ghashIterator_isDone(iter); BLI_ghashIterator_step(iter)) {
+               uiListType *ult = BLI_ghashIterator_getValue(iter);
+               if (ult->ext.free) {
+                       ult->ext.free(ult->ext.data);
+               }
+       }
+       BLI_ghashIterator_free(iter);
+
+       BLI_ghash_free(uilisttypes_hash, NULL, (GHashValFreeFP)MEM_freeN);
+       uilisttypes_hash = NULL;
+}
+
+/* ************ MenuType handling ************** */
 
 static GHash *menutypes_hash = NULL;
 
index 3cffa143ebce3e2d8ba4372bb828c7c7c6a4cf09..aae44f51f18e022a1b9fc7eb3df4a8aa45b7b309 100644 (file)
@@ -137,6 +137,7 @@ void WM_init(bContext *C, int argc, const char **argv)
        GHOST_CreateSystemPaths();
        wm_operatortype_init();
        WM_menutype_init();
+       WM_uilisttype_init();
 
        set_free_windowmanager_cb(wm_close_and_free);   /* library.c */
        set_blender_test_break_cb(wm_window_testbreak); /* blender.c */
@@ -403,6 +404,7 @@ void WM_exit_ext(bContext *C, const short do_python)
        wm_operatortype_free();
        wm_dropbox_free();
        WM_menutype_free();
+       WM_uilisttype_free();
        
        /* all non-screen and non-space stuff editors did, like editmode */
        if (C)
index 2b29129c0f749b8ecfb0673869a4c7dd3ea10da1..4b8b7460f00d65e6b88959632bffb06b4e5166c7 100644 (file)
@@ -414,7 +414,9 @@ void uiTemplateCurveMapping(struct uiLayout *layout, struct CurveMapping *cumap,
 void uiTemplateColorRamp(struct uiLayout *layout, struct ColorBand *coba, int expand) {}
 void uiTemplateLayers(struct uiLayout *layout, struct PointerRNA *ptr, char *propname) {}
 void uiTemplateImageLayers(struct uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser) {}
-ListBase uiTemplateList(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, char *propname, struct PointerRNA *activeptr, char *activepropname, int rows, int listtype) {struct ListBase b = {0,0}; return b;}
+void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, const char *list_id,
+                    PointerRNA *dataptr, const char *propname, PointerRNA *active_dataptr,
+                    const char *active_propname, int rows, int maxrows, int layout_type) {}
 void uiTemplateRunningJobs(struct uiLayout *layout, struct bContext *C) {}
 void uiTemplateOperatorSearch(struct uiLayout *layout) {}
 void uiTemplateHeader3D(struct uiLayout *layout, struct bContext *C) {}