From 1f37fae4a9a5972a873806ac6f8503ab062994be Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sun, 12 Aug 2018 19:22:34 -0400 Subject: [PATCH 1/3] Implement generic list add/remove operators Currently, this only takes the place of the texture operators. Once the generic UI code is done, this will be propagated throughout. --- korman/operators/__init__.py | 2 +- korman/operators/op_texture.py | 61 ----------------------- korman/operators/op_ui.py | 89 ++++++++++++++++++++++++++++++++++ korman/ui/ui_texture.py | 17 ++++--- 4 files changed, 100 insertions(+), 69 deletions(-) delete mode 100644 korman/operators/op_texture.py create mode 100644 korman/operators/op_ui.py diff --git a/korman/operators/__init__.py b/korman/operators/__init__.py index 94b352f..006053c 100644 --- a/korman/operators/__init__.py +++ b/korman/operators/__init__.py @@ -19,8 +19,8 @@ from . import op_mesh as mesh from . import op_modifier as modifier from . import op_nodes as nodes from . import op_sound as sound -from . import op_texture as texture from . import op_toolbox as toolbox +from . import op_ui as ui from . import op_world as world def register(): diff --git a/korman/operators/op_texture.py b/korman/operators/op_texture.py deleted file mode 100644 index 86d5391..0000000 --- a/korman/operators/op_texture.py +++ /dev/null @@ -1,61 +0,0 @@ -# This file is part of Korman. -# -# Korman is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Korman is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Korman. If not, see . - -import bpy -from bpy.props import * - -class TextureOperator: - @classmethod - def poll(cls, context): - return context.scene.render.engine == "PLASMA_GAME" and context.texture - - -class TextureCollectionAddOperator(TextureOperator, bpy.types.Operator): - bl_idname = "texture.plasma_collection_add" - bl_label = "Add Item" - bl_description = "Adds an item to the collection" - - group = StringProperty(name="Modifier", description="Attribute name of the PropertyGroup") - collection = StringProperty(name="Collection", description="Attribute name of the collection property") - name_prefix = StringProperty(name="Name Prefix", description="Prefix for autogenerated item names", default="Item") - name_prop = StringProperty(name="Name Property", description="Attribute name of the item name property") - - def execute(self, context): - mod = getattr(context.texture, self.group) - collection = getattr(mod, self.collection) - idx = len(collection) - collection.add() - if self.name_prop: - setattr(collection[idx], self.name_prop, "{} {}".format(self.name_prefix, idx+1)) - return {"FINISHED"} - - -class TextureCollectionRemoveOperator(TextureOperator, bpy.types.Operator): - bl_idname = "texture.plasma_collection_remove" - bl_label = "Remove Item" - bl_description = "Removes an item from the collection" - - group = StringProperty(name="Modifier", description="Attribute name of the PropertyGroup") - collection = StringProperty(name="Collection", description="Attribute name of the collection property") - index = IntProperty(name="Index", description="Item index to remove") - - def execute(self, context): - mod = getattr(context.texture, self.group) - collection = getattr(mod, self.collection) - if len(collection) > self.index: - collection.remove(self.index) - return {"FINISHED"} - else: - return {"CANCELLED"} diff --git a/korman/operators/op_ui.py b/korman/operators/op_ui.py new file mode 100644 index 0000000..0f23da4 --- /dev/null +++ b/korman/operators/op_ui.py @@ -0,0 +1,89 @@ +# This file is part of Korman. +# +# Korman is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Korman is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Korman. If not, see . + +import bpy +from bpy.props import * + +class UIOperator: + @classmethod + def poll(cls, context): + return context.scene.render.engine == "PLASMA_GAME" + + +class CollectionAddOperator(UIOperator, bpy.types.Operator): + bl_idname = "ui.plasma_collection_add" + bl_label = "Add Item" + bl_description = "Adds an item to the collection" + + context = StringProperty(name="ID Path", + description="Path to the relevant datablock from the current context", + options=set()) + group_path = StringProperty(name="Property Group Path", + description="Path to the property group from the ID", + options=set()) + collection_prop = StringProperty(name="Collection Property", + description="Name of the collection property", + options=set()) + index_prop = StringProperty(name="Index Property", + description="Name of the active element index property", + options=set()) + name_prefix = StringProperty(name="Name Prefix", + description="Prefix for autogenerated item names", + default="Item", + options=set()) + name_prop = StringProperty(name="Name Property", + description="Attribute name of the item name property", + options=set()) + + def execute(self, context): + props = getattr(context, self.context).path_resolve(self.group_path) + collection = getattr(props, self.collection_prop) + idx = len(collection) + collection.add() + if self.name_prop: + setattr(collection[idx], self.name_prop, "{} {}".format(self.name_prefix, idx+1)) + if self.index_prop: + setattr(props, self.index_prop, idx) + return {"FINISHED"} + + +class CollectionRemoveOperator(UIOperator, bpy.types.Operator): + bl_idname = "ui.plasma_collection_remove" + bl_label = "Remove Item" + bl_description = "Removes an item from the collection" + + context = StringProperty(name="ID Path", + description="Path to the relevant datablock from the current context", + options=set()) + group_path = StringProperty(name="Property Group Path", + description="Path to the property group from the ID", + options=set()) + collection_prop = StringProperty(name="Collection Property", + description="Name of the collection property", + options=set()) + index_prop = StringProperty(name="Index Property", + description="Name of the active element index property", + options=set()) + + def execute(self, context): + props = getattr(context, self.context).path_resolve(self.group_path) + collection = getattr(props, self.collection_prop) + index = getattr(props, self.index_prop) + if len(collection) > index: + collection.remove(index) + setattr(props, self.index_prop, index - 1) + return {"FINISHED"} + else: + return {"CANCELLED"} diff --git a/korman/ui/ui_texture.py b/korman/ui/ui_texture.py index 2bc3d7a..9821ca3 100644 --- a/korman/ui/ui_texture.py +++ b/korman/ui/ui_texture.py @@ -46,13 +46,16 @@ class PlasmaEnvMapPanel(TextureButtonsPanel, bpy.types.Panel): row.template_list("VisRegionListUI", "vis_regions", layer_props, "vis_regions", layer_props, "active_region_index", rows=2, maxrows=3) col = row.column(align=True) - op = col.operator("texture.plasma_collection_add", icon="ZOOMIN", text="") - op.group = "plasma_layer" - op.collection = "vis_regions" - op = col.operator("texture.plasma_collection_remove", icon="ZOOMOUT", text="") - op.group = "plasma_layer" - op.collection = "vis_regions" - op.index = layer_props.active_region_index + op = col.operator("ui.plasma_collection_add", icon="ZOOMIN", text="") + op.context = "texture" + op.group_path = "plasma_layer" + op.collection_prop = "vis_regions" + op.index_prop = "active_region_index" + op = col.operator("ui.plasma_collection_remove", icon="ZOOMOUT", text="") + op.context = "texture" + op.group_path = "plasma_layer" + op.collection_prop = "vis_regions" + op.index_prop = "active_region_index" rgns = layer_props.vis_regions if layer_props.vis_regions: layout.prop(rgns[layer_props.active_region_index], "control_region") From f8aafcf3f1c2001bda005f8e7d125cd83b8bd867 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sun, 12 Aug 2018 19:48:11 -0400 Subject: [PATCH 2/3] Implement standard UI List draw function Same as before, only doing Textures right now. --- korman/ui/__init__.py | 1 + korman/ui/ui_list.py | 46 +++++++++++++++++++++++++++++++++++++++++ korman/ui/ui_texture.py | 18 ++++------------ 3 files changed, 51 insertions(+), 14 deletions(-) create mode 100644 korman/ui/ui_list.py diff --git a/korman/ui/__init__.py b/korman/ui/__init__.py index c334f8a..c1f3e3f 100644 --- a/korman/ui/__init__.py +++ b/korman/ui/__init__.py @@ -14,6 +14,7 @@ # along with Korman. If not, see . from .ui_lamp import * +from .ui_list import * from .ui_menus import * from .ui_modifiers import * from .ui_object import * diff --git a/korman/ui/ui_list.py b/korman/ui/ui_list.py new file mode 100644 index 0000000..261c4dc --- /dev/null +++ b/korman/ui/ui_list.py @@ -0,0 +1,46 @@ +# This file is part of Korman. +# +# Korman is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Korman is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Korman. If not, see . + +import bpy + +def draw_list(layout, listtype, context_attr, prop_base, collection_name, index_name, **kwargs): + """Draws a generic UI list, including add/remove buttons. Note that in order to use this, + the parent datablock must be available in the context provided to operators. This should + always be true, but this is Blender... + Arguments: + - layout: required + - listtype: bpy.types.UIList subclass + - context_attr: attribute name to get the properties from in the current context + - prop_base: property group owning the collection + - collection_name: name of the collection property + - index_name: name of the active element index property + *** any other arguments are passed as keyword arguments to the template_list call + """ + prop_path = prop_base.path_from_id() + row = layout.row() + row.template_list(listtype, collection_name, prop_base, collection_name, + prop_base, index_name, **kwargs) + col = row.column(align=True) + op = col.operator("ui.plasma_collection_add", icon="ZOOMIN", text="") + op.context = context_attr + op.group_path = prop_path + op.collection_prop = collection_name + op.index_prop = index_name + op = col.operator("ui.plasma_collection_remove", icon="ZOOMOUT", text="") + op.context = context_attr + op.group_path = prop_path + op.collection_prop = collection_name + op.index_prop = index_name + diff --git a/korman/ui/ui_texture.py b/korman/ui/ui_texture.py index 9821ca3..80b5d20 100644 --- a/korman/ui/ui_texture.py +++ b/korman/ui/ui_texture.py @@ -15,6 +15,8 @@ import bpy +from . import ui_list + class TextureButtonsPanel: bl_space_type = "PROPERTIES" bl_region_type = "WINDOW" @@ -42,20 +44,8 @@ class PlasmaEnvMapPanel(TextureButtonsPanel, bpy.types.Panel): layout.separator() layout.label("Visibility Sets:") - row = layout.row() - row.template_list("VisRegionListUI", "vis_regions", layer_props, "vis_regions", layer_props, "active_region_index", - rows=2, maxrows=3) - col = row.column(align=True) - op = col.operator("ui.plasma_collection_add", icon="ZOOMIN", text="") - op.context = "texture" - op.group_path = "plasma_layer" - op.collection_prop = "vis_regions" - op.index_prop = "active_region_index" - op = col.operator("ui.plasma_collection_remove", icon="ZOOMOUT", text="") - op.context = "texture" - op.group_path = "plasma_layer" - op.collection_prop = "vis_regions" - op.index_prop = "active_region_index" + ui_list.draw_list(layout, "VisRegionListUI", "texture", layer_props, + "vis_regions", "active_region_index", rows=2, maxrows=3) rgns = layer_props.vis_regions if layer_props.vis_regions: layout.prop(rgns[layer_props.active_region_index], "control_region") From 25e8a828754e8311a0c59745d76e60f79a8435a2 Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Sun, 12 Aug 2018 21:02:44 -0400 Subject: [PATCH 3/3] Convert all modifier lists to ui_list The world lists (pages and games) require special operators, so it seems best to just leave them as they are for now. --- korman/operators/op_modifier.py | 41 --------------------------------- korman/ui/modifiers/anim.py | 33 ++++++-------------------- korman/ui/modifiers/logic.py | 22 ++++++------------ korman/ui/modifiers/render.py | 15 ++++-------- korman/ui/modifiers/sound.py | 15 ++++-------- korman/ui/modifiers/water.py | 18 ++++----------- korman/ui/ui_list.py | 9 ++++++++ 7 files changed, 36 insertions(+), 117 deletions(-) diff --git a/korman/operators/op_modifier.py b/korman/operators/op_modifier.py index f640bfc..82292c2 100644 --- a/korman/operators/op_modifier.py +++ b/korman/operators/op_modifier.py @@ -233,44 +233,3 @@ class ModifierLogicWizOperator(ModifierOperator, bpy.types.Operator): end = time.process_time() print("\nLogicWiz finished in {:.2f} seconds".format(end-start)) return {"FINISHED"} - - -class ModifierCollectionAddOperator(ModifierOperator, bpy.types.Operator): - bl_idname = "object.plasma_modifier_collection_add" - bl_label = "Add Item" - bl_description = "Adds an item to the collection" - - modifier = StringProperty(name="Modifier", description="Attribute name of the Plasma Modifier") - collection = StringProperty(name="Collection", description="Attribute name of the collection property") - name_prefix = StringProperty(name="Name Prefix", description="Prefix for autogenerated item names", default="Item") - name_prop = StringProperty(name="Name Property", description="Attribute name of the item name property") - - def execute(self, context): - obj = context.active_object - mod = getattr(obj.plasma_modifiers, self.modifier) - collection = getattr(mod, self.collection) - idx = len(collection) - collection.add() - if self.name_prop: - setattr(collection[idx], self.name_prop, "{} {}".format(self.name_prefix, idx+1)) - return {"FINISHED"} - - -class ModifierCollectionRemoveOperator(ModifierOperator, bpy.types.Operator): - bl_idname = "object.plasma_modifier_collection_remove" - bl_label = "Remove Item" - bl_description = "Removes an item from the collection" - - modifier = StringProperty(name="Modifier", description="Attribute name of the Plasma Modifier") - collection = StringProperty(name="Collection", description="Attribute name of the collection property") - index = IntProperty(name="Index", description="Item index to remove") - - def execute(self, context): - obj = context.active_object - mod = getattr(obj.plasma_modifiers, self.modifier) - collection = getattr(mod, self.collection) - if len(collection) > self.index: - collection.remove(self.index) - return {"FINISHED"} - else: - return {"CANCELLED"} diff --git a/korman/ui/modifiers/anim.py b/korman/ui/modifiers/anim.py index 681e43a..5216dda 100644 --- a/korman/ui/modifiers/anim.py +++ b/korman/ui/modifiers/anim.py @@ -15,6 +15,8 @@ import bpy +from .. import ui_list + def _check_for_anim(layout, modifier): try: action = modifier.blender_action @@ -67,18 +69,8 @@ def animation_group(modifier, layout, context): if action is None: return - row = layout.row() - row.template_list("GroupListUI", "children", modifier, "children", modifier, "active_child_index", - rows=3, maxrows=4) - col = row.column(align=True) - op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") - op.modifier = modifier.pl_id - op.collection = "children" - op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") - op.modifier = modifier.pl_id - op.collection = "children" - op.index = modifier.active_child_index - + ui_list.draw_modifier_list(layout, "GroupListUI", modifier, "children", + "active_child_index", rows=3, maxrows=4) if modifier.children: layout.prop(modifier.children[modifier.active_child_index], "child_anim", icon="ACTION") @@ -96,20 +88,9 @@ def animation_loop(modifier, layout, context): elif action is None: return - row = layout.row() - row.template_list("LoopListUI", "loops", modifier, "loops", modifier, "active_loop_index", - rows=2, maxrows=3) - col = row.column(align=True) - op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") - op.modifier = modifier.pl_id - op.collection = "loops" - op.name_prefix = "Loop" - op.name_prop = "loop_name" - op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") - op.modifier = modifier.pl_id - op.collection = "loops" - op.index = modifier.active_loop_index - + ui_list.draw_modifier_list(layout, "LoopListUI", modifier, "loops", + "active_loop_index", name_prefix="Loop", + name_prop="loop_name", rows=2, maxrows=3) # Modify the loop points if modifier.loops: loop = modifier.loops[modifier.active_loop_index] diff --git a/korman/ui/modifiers/logic.py b/korman/ui/modifiers/logic.py index c96f675..2a789a1 100644 --- a/korman/ui/modifiers/logic.py +++ b/korman/ui/modifiers/logic.py @@ -15,27 +15,19 @@ import bpy +from .. import ui_list + class LogicListUI(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_property, index=0, flt_flag=0): layout.prop(item, "name", emboss=False, text="", icon="NODETREE") def advanced_logic(modifier, layout, context): - row = layout.row() - row.template_list("LogicListUI", "logic_groups", modifier, "logic_groups", modifier, "active_group_index", - rows=2, maxrows=3) - col = row.column(align=True) - op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") - op.modifier = modifier.pl_id - op.collection = "logic_groups" - op.name_prefix = "Logic" - op.name_prop = "name" - op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") - op.modifier = modifier.pl_id - op.collection = "logic_groups" - op.index = modifier.active_group_index - - # Modify the loop points + ui_list.draw_modifier_list(layout, "LogicListUI", modifier, "logic_groups", + "active_group_index", name_prefix="Logic", + name_prop="name", rows=2, maxrows=3) + + # Modify the logic groups if modifier.logic_groups: logic = modifier.logic_groups[modifier.active_group_index] layout.row().prop_menu_enum(logic, "version") diff --git a/korman/ui/modifiers/render.py b/korman/ui/modifiers/render.py index be79b78..df55ee4 100644 --- a/korman/ui/modifiers/render.py +++ b/korman/ui/modifiers/render.py @@ -15,6 +15,8 @@ import bpy +from .. import ui_list + def fademod(modifier, layout, context): layout.prop(modifier, "fader_type") @@ -147,17 +149,8 @@ class VisRegionListUI(bpy.types.UIList): def visibility(modifier, layout, context): - row = layout.row() - row.template_list("VisRegionListUI", "regions", modifier, "regions", modifier, "active_region_index", - rows=2, maxrows=3) - col = row.column(align=True) - op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") - op.modifier = modifier.pl_id - op.collection = "regions" - op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") - op.modifier = modifier.pl_id - op.collection = "regions" - op.index = modifier.active_region_index + ui_list.draw_modifier_list(layout, "VisRegionListUI", modifier, "regions", + "active_region_index", rows=2, maxrows=3) if modifier.regions: layout.prop(modifier.regions[modifier.active_region_index], "control_region") diff --git a/korman/ui/modifiers/sound.py b/korman/ui/modifiers/sound.py index 376a29e..e51b383 100644 --- a/korman/ui/modifiers/sound.py +++ b/korman/ui/modifiers/sound.py @@ -15,6 +15,8 @@ import bpy +from .. import ui_list + def _draw_fade_ui(modifier, layout, label): layout.label(label) layout.prop(modifier, "fade_type", text="") @@ -30,17 +32,8 @@ class SoundListUI(bpy.types.UIList): def soundemit(modifier, layout, context): - row = layout.row() - row.template_list("SoundListUI", "sounds", modifier, "sounds", modifier, "active_sound_index", - rows=2, maxrows=3) - col = row.column(align=True) - op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") - op.modifier = modifier.pl_id - op.collection = "sounds" - op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") - op.modifier = modifier.pl_id - op.collection = "sounds" - op.index = modifier.active_sound_index + ui_list.draw_modifier_list(layout, "SoundListUI", modifier, "sounds", + "active_sound_index", rows=2, maxrows=3) try: sound = modifier.sounds[modifier.active_sound_index] diff --git a/korman/ui/modifiers/water.py b/korman/ui/modifiers/water.py index f6dec6f..08313b9 100644 --- a/korman/ui/modifiers/water.py +++ b/korman/ui/modifiers/water.py @@ -15,6 +15,8 @@ import bpy +from .. import ui_list + def swimregion(modifier, layout, context): split = layout.split() col = split.column() @@ -111,19 +113,9 @@ class ShoreListUI(bpy.types.UIList): def water_shore(modifier, layout, context): - row = layout.row() - row.template_list("ShoreListUI", "shores", modifier, "shores", modifier, "active_shore_index", - rows=2, maxrows=3) - col = row.column(align=True) - op = col.operator("object.plasma_modifier_collection_add", icon="ZOOMIN", text="") - op.modifier = modifier.pl_id - op.collection = "shores" - op.name_prefix = "Shore" - op.name_prop = "display_name" - op = col.operator("object.plasma_modifier_collection_remove", icon="ZOOMOUT", text="") - op.modifier = modifier.pl_id - op.collection = "shores" - op.index = modifier.active_shore_index + ui_list.draw_modifier_list(layout, "ShoreListUI", modifier, "shores", + "active_shore_index", name_prefix="Shore", + name_prop="display_name", rows=2, maxrows=3) # Display the active shore if modifier.shores: diff --git a/korman/ui/ui_list.py b/korman/ui/ui_list.py index 261c4dc..7f7e032 100644 --- a/korman/ui/ui_list.py +++ b/korman/ui/ui_list.py @@ -26,9 +26,14 @@ def draw_list(layout, listtype, context_attr, prop_base, collection_name, index_ - prop_base: property group owning the collection - collection_name: name of the collection property - index_name: name of the active element index property + - name_prefix: (optional) prefix to apply to display name of new elements + - name_prop: (optional) property for each element's display name *** any other arguments are passed as keyword arguments to the template_list call """ prop_path = prop_base.path_from_id() + name_prefix = kwargs.pop("name_prefix", "") + name_prop = kwargs.pop("name_prop", "") + row = layout.row() row.template_list(listtype, collection_name, prop_base, collection_name, prop_base, index_name, **kwargs) @@ -38,9 +43,13 @@ def draw_list(layout, listtype, context_attr, prop_base, collection_name, index_ op.group_path = prop_path op.collection_prop = collection_name op.index_prop = index_name + op.name_prefix = name_prefix + op.name_prop = name_prop op = col.operator("ui.plasma_collection_remove", icon="ZOOMOUT", text="") op.context = context_attr op.group_path = prop_path op.collection_prop = collection_name op.index_prop = index_name +def draw_modifier_list(layout, listtype, prop_base, collection_name, index_name, **kwargs): + draw_list(layout, listtype, "object", prop_base, collection_name, index_name, **kwargs)