Browse Source

Add mouse click/over animations to GUI Buttons.

pull/373/head
Adam Johnson 10 months ago
parent
commit
bc9c6fd63d
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 123
      korman/properties/modifiers/game_gui.py
  2. 83
      korman/ui/modifiers/game_gui.py

123
korman/properties/modifiers/game_gui.py

@ -191,6 +191,122 @@ class PlasmaGameGuiControlModifier(PlasmaModifierProperties, _GameGuiMixin):
return False
class GameGuiAnimation(bpy.types.PropertyGroup):
def _poll_target_object(self, value):
# Only allow targetting things that are in our GUI page.
if value.plasma_object.page != self.id_data.plasma_object.page:
return False
if self.anim_type == "OBJECT":
return idprops.poll_animated_objects(self, value)
else:
return idprops.poll_drawable_objects(self, value)
def _poll_texture(self, value):
# must be a legal option... but is it a member of this material... or, if no material,
# any of the materials attached to the object?
if self.target_material is not None:
return value.name in self.target_material.texture_slots
else:
target_object = self.target_object if self.target_object is not None else self.id_data
for i in (slot.material for slot in target_object.material_slots if slot and slot.material):
if value in (slot.texture for slot in i.texture_slots if slot and slot.texture):
return True
return False
def _poll_material(self, value):
# Don't filter materials by texture - this would (potentially) result in surprising UX
# in that you would have to clear the texture selection before being able to select
# certain materials.
target_object = self.target_object if self.target_object is not None else self.id_data
object_materials = (slot.material for slot in target_object.material_slots if slot and slot.material)
return value in object_materials
anim_type: str = EnumProperty(
name="Type",
description="Animation type to affect",
items=[
("OBJECT", "Object", "Object Animation"),
("TEXTURE", "Texture", "Texture Animation"),
],
default="OBJECT",
options=set()
)
target_object: bpy.types.Object = PointerProperty(
name="Object",
description="Target object",
poll=_poll_target_object,
type=bpy.types.Object
)
target_material: bpy.types.Material = PointerProperty(
name="Material",
description="Target material",
type=bpy.types.Material,
poll=_poll_material
)
target_texture: bpy.types.Texture = PointerProperty(
name="Texture",
description="Target texture",
type=bpy.types.Texture,
poll=_poll_texture
)
class GameGuiAnimationGroup(bpy.types.PropertyGroup):
def _update_animation_name(self, context) -> None:
if not self.animation_name:
self.animation_name = "(Entire Animation)"
animations = CollectionProperty(
name="Animations",
description="",
type=GameGuiAnimation,
options=set()
)
animation_name: str = StringProperty(
name="Animation Name",
description="Name of the animation to play",
default="(Entire Animation)",
update=_update_animation_name,
options=set()
)
active_anim_index: int = IntProperty(options={"HIDDEN"})
show_expanded: bool = BoolProperty(options={"HIDDEN"})
def export(
self, exporter: Exporter, bo: bpy.types.Object, so: plSceneObject,
ctrl_obj: pfGUIControlMod, add_func: Callable[[plKey], None],
anim_name_attr: str
):
keys = set()
for anim in self.animations:
target_object = anim.target_object if anim.target_object is not None else bo
if anim.anim_type == "OBJECT":
keys.add(exporter.animation.get_animation_key(target_object))
elif anim.anim_type == "TEXTURE":
# Layer animations don't respect the name field, so we need to grab exactly the
# layer animation key that is requested. Cyan's Max plugin does not allow specifying
# layer animations here as best I can tell, but I don't see why we shouldn't.
keys.update(
exporter.mesh.material.get_texture_animation_key(
target_object,
anim.target_material,
anim.target_texture,
self.animation_name
)
)
else:
raise RuntimeError()
# This is to make sure that we only waste space in the PRP file with the animation
# name if we actually have some doggone animations.
if keys:
setattr(ctrl_obj, anim_name_attr, self.animation_name)
for i in keys:
add_func(i)
class PlasmaGameGuiButtonModifier(PlasmaModifierProperties, _GameGuiMixin):
pl_id = "gui_button"
pl_depends = {"gui_control"}
@ -217,6 +333,10 @@ class PlasmaGameGuiButtonModifier(PlasmaModifierProperties, _GameGuiMixin):
update=_update_notify_type
)
mouse_over_anims: GameGuiAnimationGroup = PointerProperty(type=GameGuiAnimationGroup)
mouse_click_anims: GameGuiAnimationGroup = PointerProperty(type=GameGuiAnimationGroup)
show_expanded_sounds: bool = BoolProperty(options={"HIDDEN"})
mouse_down_sound: str = StringProperty(
name="Mouse Down SFX",
description="Sound played when the mouse button is down",
@ -266,6 +386,9 @@ class PlasmaGameGuiButtonModifier(PlasmaModifierProperties, _GameGuiMixin):
else:
raise ValueError(self.notify_type)
self.mouse_over_anims.export(exporter, bo, so, ctrl, ctrl.addMouseOverKey, "mouseOverAnimName")
self.mouse_click_anims.export(exporter, bo, so, ctrl, ctrl.addAnimationKey, "animName")
class PlasmaGameGuiDialogModifier(PlasmaModifierProperties, _GameGuiMixin):
pl_id = "gui_dialog"

83
korman/ui/modifiers/game_gui.py

@ -13,19 +13,86 @@
# You should have received a copy of the GNU General Public License
# along with Korman. If not, see <http://www.gnu.org/licenses/>.
from __future__ import annotations
from typing import *
import bpy.types
from .. import ui_list
if TYPE_CHECKING:
from ...properties.modifiers.game_gui import GameGuiAnimation, GameGuiAnimationGroup
class GuiAnimListUI(bpy.types.UIList):
def _iter_target_names(self, item: GameGuiAnimation):
if item.target_object is not None:
yield item.target_object.name
else:
yield item.id_data.name
if item.target_material is not None:
yield item.target_material.name
if item.target_texture is not None:
yield item.target_texture.name
def draw_item(
self, context, layout, data, item: GameGuiAnimation, icon, active_data,
active_property, index=0, flt_flag=0
):
if item.anim_type == "OBJECT":
name = item.target_object.name if item.target_object is not None else item.id_data.name
layout.label(name, icon="OBJECT_DATA")
elif item.anim_type == "TEXTURE":
name_seq = list(self._iter_target_names(item))
layout.label(" / ".join(name_seq), icon="TEXTURE")
else:
raise RuntimeError()
def _gui_anim(name: str, group: GameGuiAnimationGroup, layout, context):
box = layout.box()
row = box.row(align=True)
exicon = "TRIA_DOWN" if group.show_expanded else "TRIA_RIGHT"
row.prop(group, "show_expanded", text="", icon=exicon, emboss=False)
row.prop(group, "animation_name", text=name, icon="ANIM")
if not group.show_expanded:
return
ui_list.draw_modifier_list(box, "GuiAnimListUI", group, "animations", "active_anim_index", rows=2)
try:
anim: GameGuiAnimation = group.animations[group.active_anim_index]
except:
pass
else:
col = box.column()
col.prop(anim, "anim_type")
col.prop(anim, "target_object")
if anim.anim_type == "TEXTURE":
col.prop(anim, "target_material")
col.prop(anim, "target_texture")
def gui_button(modifier, layout, context):
row = layout.row()
row.label("Notify On:")
row.prop(modifier, "notify_type")
soundemit = modifier.id_data.plasma_modifiers.soundemit
col = layout.column()
col.label("Sound Effects:")
col.active = soundemit.enabled
col.prop_search(modifier, "mouse_down_sound", soundemit, "sounds", text="Mouse Down", icon="SPEAKER")
col.prop_search(modifier, "mouse_up_sound", soundemit, "sounds", text="Mouse Up", icon="SPEAKER")
col.prop_search(modifier, "mouse_over_sound", soundemit, "sounds", text="Mouse Over", icon="SPEAKER")
col.prop_search(modifier, "mouse_off_sound", soundemit, "sounds", text="Mouse Off", icon="SPEAKER")
_gui_anim("Mouse Click", modifier.mouse_click_anims, layout, context)
_gui_anim("Mouse Over", modifier.mouse_over_anims, layout, context)
box = layout.box()
row = box.row(align=True)
exicon = "TRIA_DOWN" if modifier.show_expanded_sounds else "TRIA_RIGHT"
row.prop(modifier, "show_expanded_sounds", text="", icon=exicon, emboss=False)
row.label("Sound Effects")
if modifier.show_expanded_sounds:
col = box.column()
soundemit = modifier.id_data.plasma_modifiers.soundemit
col.active = soundemit.enabled
col.prop_search(modifier, "mouse_down_sound", soundemit, "sounds", text="Mouse Down", icon="SPEAKER")
col.prop_search(modifier, "mouse_up_sound", soundemit, "sounds", text="Mouse Up", icon="SPEAKER")
col.prop_search(modifier, "mouse_over_sound", soundemit, "sounds", text="Mouse Over", icon="SPEAKER")
col.prop_search(modifier, "mouse_off_sound", soundemit, "sounds", text="Mouse Off", icon="SPEAKER")
def gui_control(modifier, layout, context):
split = layout.split()

Loading…
Cancel
Save