diff --git a/editor-blender/api/led_agent.py b/editor-blender/api/led_agent.py index 622ca6b85..975e48c32 100644 --- a/editor-blender/api/led_agent.py +++ b/editor-blender/api/led_agent.py @@ -7,14 +7,18 @@ from ..core.utils.convert import led_map_query_to_state from ..graphqls.mutations import ( ADD_LED_EFFECT, + CANCEL_EDIT_LED_EFFECT_BY_ID, DELETE_LED_EFFECT, EDIT_LED_EFFECT, + REQUEST_EDIT_LED_EFFECT_BY_ID, MutAddLEDEffectInput, MutAddLEDEffectResponse, + MutCancelEditLEDEffectResponse, MutDeleteLEDEffectResponse, MutEditLEDEffectInput, MutEditLEDEffectResponse, MutLEDEffectFramePayload, + MutRequestEditLEDEffectResponse, ) from ..graphqls.queries import GET_LED_MAP, QueryLEDMapData @@ -69,7 +73,7 @@ async def add_led_effect( return None - async def edit_led_effect( + async def save_led_effect( self, id: ID, name: str, leds: List[Tuple[ColorID, int]] ) -> Optional[MutEditLEDEffectResponse]: try: @@ -97,6 +101,40 @@ async def edit_led_effect( return None + async def request_edit(self, id: LEDEffectID) -> Optional[bool]: + try: + response = await client.execute( + MutRequestEditLEDEffectResponse, + REQUEST_EDIT_LED_EFFECT_BY_ID, + {"ledEffectId": id}, + ) + return response["RequestEditLEDEffect"].ok + + except asyncio.CancelledError: + pass + + except Exception as e: + print(e) + + return None + + async def cancel_edit(self, id: LEDEffectID) -> Optional[bool]: + try: + response = await client.execute( + MutCancelEditLEDEffectResponse, + CANCEL_EDIT_LED_EFFECT_BY_ID, + {"ledEffectId": id}, + ) + return response["CancelEditLEDEffect"].ok + + except asyncio.CancelledError: + pass + + except Exception as e: + print(e) + + return None + async def delete_led_effect( self, id: LEDEffectID ) -> Optional[MutDeleteLEDEffectResponse]: diff --git a/editor-blender/client/subscription.py b/editor-blender/client/subscription.py index 1943dbf65..6bab52434 100644 --- a/editor-blender/client/subscription.py +++ b/editor-blender/client/subscription.py @@ -10,13 +10,19 @@ set_control_record, update_control, ) +from ..core.actions.state.led_map import ( + add_led_effect, + delete_led_effect, + edit_led_effect, +) from ..core.actions.state.pos_map import add_pos, delete_pos, set_pos_record, update_pos -from ..core.models import ID +from ..core.models import ID, LEDMap from ..core.utils.convert import ( color_query_to_state, control_frame_query_to_state, control_frame_sub_to_query, effect_list_data_sub_to_query, + led_record_sub_to_state_item, pos_frame_query_to_state, pos_frame_sub_to_query, ) @@ -34,6 +40,7 @@ SUB_CONTROL_MAP, SUB_CONTROL_RECORD, SUB_EFFECT_LIST, + SUB_LED_RECORD, SUB_POS_MAP, SUB_POS_RECORD, SubColorData, @@ -42,6 +49,7 @@ SubControlRecordData, SubEffectListData, SubEffectListMutation, + SubLEDRecordData, SubPositionMapData, SubPositionRecordData, ) @@ -243,6 +251,42 @@ async def modifier(effectList: Optional[QueryEffectListData]): await client.cache.modify(Modifiers(fields={"effectList": modifier})) +async def sub_led_record(client: Clients): + async for data in client.subscribe(SubLEDRecordData, SUB_LED_RECORD): + print("SubEffectRecord:", data) + + async def modifier(LedMap: Optional[LEDMap]): + subscriptionData = data["ledRecordSubscription"] + + newLedMap: LEDMap = {} + if LedMap is not None: + newLedMap = LedMap + + for item in subscriptionData.createEffects: + effect_item = led_record_sub_to_state_item(item) + # newLedMap[item.model_name][item.part_name][item.name] = effect_item + add_led_effect(item.model_name, item.part_name, item.name, effect_item) + + for item in subscriptionData.deleteEffects: + # delete_name = next(name for name, effect in newLedMap[item.model_name][item.part_name].items() if effect.id == item.id) + # del newLedMap[item.model_name][item.part_name][delete_name] + delete_led_effect(item.model_name, item.part_name, item.id) + + for item in subscriptionData.updateEffects: + # edited_name = next(name for name, effect in newLedMap[item.model_name][item.part_name].items() if effect.id == item.id) + effect_item = led_record_sub_to_state_item(item) + # if item.name == edited_name: + # newLedMap[item.model_name][item.part_name][edited_name] = effect_item + # else: + # del newLedMap[item.model_name][item.part_name][edited_name] + # newLedMap[item.model_name][item.part_name][item.name] = effect_item + edit_led_effect(item.model_name, item.part_name, item.name, effect_item) + + return newLedMap + + await client.cache.modify(Modifiers(fields={"LEDMap": modifier})) + + # TODO: Implement lazy update async def sub_color_map(client: Clients): async for data in client.subscribe(SubColorData, SUB_COLOR_MAP): @@ -306,6 +350,7 @@ async def subscribe(): # asyncio.create_task(sub_control_record(client)), asyncio.create_task(sub_control_map(client)), # asyncio.create_task(sub_effect_list(client)), + asyncio.create_task(sub_led_record(client)), asyncio.create_task(sub_color_map(client)), ] diff --git a/editor-blender/core/actions/property/led_editor.py b/editor-blender/core/actions/property/led_editor.py index 5e7b3d6a2..738217414 100644 --- a/editor-blender/core/actions/property/led_editor.py +++ b/editor-blender/core/actions/property/led_editor.py @@ -35,6 +35,11 @@ def update_edit_part(self: bpy.types.PropertyGroup, context: bpy.types.Context): bpy.context.view_layer.objects.active = part_obj +def update_edit_effect(self: bpy.types.PropertyGroup, context: bpy.types.Context): + effect_index = self["edit_effect"] + state.current_led_index = effect_index + + def update_multi_select_color( self: bpy.types.PropertyGroup, context: bpy.types.Context ): diff --git a/editor-blender/core/actions/state/control_editor.py b/editor-blender/core/actions/state/control_editor.py index b9c52d4d5..bfba16033 100644 --- a/editor-blender/core/actions/state/control_editor.py +++ b/editor-blender/core/actions/state/control_editor.py @@ -186,7 +186,7 @@ async def request_edit_control(): redraw_area({"VIEW_3D", "DOPESHEET_EDITOR"}) else: - notify("WARNING", "Cannot cancel edit") + notify("WARNING", "Edit request rejected") async def cancel_edit_control(): diff --git a/editor-blender/core/actions/state/led_editor.py b/editor-blender/core/actions/state/led_editor.py index 3b74d3b88..d86678d75 100644 --- a/editor-blender/core/actions/state/led_editor.py +++ b/editor-blender/core/actions/state/led_editor.py @@ -1,8 +1,9 @@ -from typing import Optional +from typing import List, Tuple import bpy -from ....core.models import EditMode +from ....api.led_agent import led_agent +from ....core.models import ColorID, EditMode, LEDEffect from ....core.states import state from ....core.utils.operator import execute_operator from ....core.utils.ui import ( @@ -15,24 +16,138 @@ unset_outliner_hide_mode_column, ) from ....properties.ui.types import LEDEditorEditModeType, LEDEditorStatusType +from ...utils.notification import notify +from .app_state import set_requesting + + +async def add_led_effect(): + ld_ui_led_editor: LEDEditorStatusType = getattr( + bpy.context.window_manager, "ld_ui_led_editor" + ) + state.edit_state = EditMode.EDITING + ld_ui_led_editor.edit_mode = LEDEditorEditModeType.NEW.value + ld_ui_led_editor.new_effect = "New effect" async def request_edit_led_effect(): - # TODO: Send request - enter_editing_led_effect() + led_index = state.current_led_index + set_requesting(True) + ok = await led_agent.request_edit(led_index) + set_requesting(False) + if ok is not None and ok: + enter_editing_led_effect() + else: + notify("WARNING", "Edit request rejected") async def cancel_edit_led_effect(): - # TODO: Send request - exit_editing_led_effect() + ld_ui_led_editor: LEDEditorStatusType = getattr( + bpy.context.window_manager, "ld_ui_led_editor" + ) + led_index = state.current_led_index + edit_mode = ld_ui_led_editor.edit_mode + match edit_mode: + case LEDEditorEditModeType.EDIT.value: + set_requesting(True) + ok = await led_agent.cancel_edit(led_index) + set_requesting(False) + if ok is not None and ok: + exit_editing_led_effect() + notify("INFO", "Edit cancelled") + else: + notify("WARNING", "Cannot cancel edit") + case LEDEditorEditModeType.NEW.value: + state.edit_state = EditMode.IDLE + ld_ui_led_editor.edit_mode = LEDEditorEditModeType.IDLE.value async def save_led_effect(): - pass + ld_ui_led_editor: LEDEditorStatusType = getattr( + bpy.context.window_manager, "ld_ui_led_editor" + ) + edit_mode = ld_ui_led_editor.edit_mode + match edit_mode: + case LEDEditorEditModeType.EDIT.value: + led_index = state.current_led_index + led_effect = state.led_effect_id_table[led_index] + effect_name = led_effect.name + edit_dancer = ld_ui_led_editor.edit_dancer + edit_part = ld_ui_led_editor.edit_part + dancer_index = state.dancer_names.index(edit_dancer) + part_obj_name = f"{dancer_index}_" + edit_part + part_obj: bpy.types.Object = bpy.data.objects.get(part_obj_name) # type: ignore + part_child_objs = part_obj.children + new_effect: List[Tuple[ColorID, int]] = [(-1, 0)] * len(part_child_objs) + for i, obj in enumerate(part_child_objs): + if obj: + ld_color: ColorID = obj.get("ld_color") # type: ignore # must use get + ld_alpha: int = getattr(obj, "ld_alpha") # type: ignore # must use getattr + new_effect[i] = (ld_color, ld_alpha) + else: + raise Exception(f"LED bulb object missing in {part_obj_name}") + try: + set_requesting(True) + await led_agent.save_led_effect(led_index, effect_name, new_effect) + notify("INFO", "Saved LED Effect") + + # Imediately apply changes produced by editing + # set_ctrl_keyframes_from_state(effect_only=True) + + # Cancel editing + ok = await led_agent.cancel_edit(led_index) + set_requesting(False) + if ok is not None and ok: + exit_editing_led_effect() + else: + notify("WARNING", "Cannot exit editing") + except: + notify("WARNING", "Cannot save LED effect") + case LEDEditorEditModeType.NEW.value: + new_effect_name = ld_ui_led_editor.new_effect + edit_model = ld_ui_led_editor.edit_model + edit_dancer = ld_ui_led_editor.edit_dancer + edit_part = ld_ui_led_editor.edit_part + part_effect: LEDEffect = next( + effect for _, effect in state.led_map[edit_model][edit_part].items() + ) + led_default = [ + (bulb_data.color_id, bulb_data.alpha) + for bulb_data in part_effect.effect + ] + + try: + set_requesting(True) + res = await led_agent.add_led_effect( + new_effect_name, edit_model, edit_part, led_default + ) + set_requesting(False) + if res and res.ok: + notify("INFO", f"Added LED Effect: {new_effect_name}") + state.edit_state = EditMode.IDLE + setattr( + ld_ui_led_editor, "edit_mode", LEDEditorEditModeType.IDLE.value + ) + else: + notify("WARNING", "Cannot add LED effect") + except: + notify("WARNING", "Cannot add LED effect") async def delete_led_effect(): - pass + led_index = state.current_led_index + if led_index == -1: + notify("WARNING", "No LED effect is selected!") + return + try: + set_requesting(True) + res = await led_agent.delete_led_effect(led_index) + set_requesting(False) + if res and res.ok: + notify("INFO", f"Deleted LED effect: {led_index}") + else: + notify("WARNING", "Cannot delete LED effect") + except: + notify("WARNING", "Cannot delete LED effect") def enter_editing_led_effect(): @@ -66,7 +181,7 @@ def enter_editing_led_effect(): dancer_obj.animation_data.action.fcurves.find("location", index=i).mute = True for bulb_obj in part_obj.children: - for i in range(4): + for i in range(3): bulb_obj.animation_data.action.fcurves.find("color", index=i).mute = True # Only select human and bulbs for local view @@ -111,7 +226,7 @@ def exit_editing_led_effect(): dancer_obj.animation_data.action.fcurves.find("location", index=i).mute = False for bulb_obj in part_obj.children: - for i in range(4): + for i in range(3): bulb_obj.animation_data.action.fcurves.find("color", index=i).mute = False # Reset pos and color of dancer and LED bulbs diff --git a/editor-blender/core/actions/state/led_map.py b/editor-blender/core/actions/state/led_map.py index 97c1cb39d..28134afe2 100644 --- a/editor-blender/core/actions/state/led_map.py +++ b/editor-blender/core/actions/state/led_map.py @@ -1,7 +1,7 @@ -from ...models import LEDMap +from ...models import LEDEffect, LEDMap from ...states import state -from ...utils.notification import notify from ...utils.ui import redraw_area +from ..property.animation_data import set_ctrl_keyframes_from_state def set_led_map(led_map: LEDMap): @@ -15,3 +15,45 @@ def set_led_map(led_map: LEDMap): # TODO: Setup LED Effect List redraw_area({"VIEW_3D", "DOPESHEET_EDITOR"}) + + +def add_led_effect( + model_name: str, part_name: str, effect_name: str, effect_item: LEDEffect +): + led_map = state.led_map + led_map[model_name][part_name][effect_name] = effect_item + set_led_map(led_map) + + +def edit_led_effect( + model_name: str, part_name: str, effect_name: str, effect_item: LEDEffect +): + led_map = state.led_map + edited_name = next( + name + for name, effect in led_map[model_name][part_name].items() + if effect.id == effect_item.id + ) + if effect_name == edited_name: + led_map[model_name][part_name][edited_name] = effect_item + else: + del led_map[model_name][part_name][edited_name] + led_map[model_name][part_name][effect_name] = effect_item + state.led_map_pending = True + set_led_map(led_map) + + +def delete_led_effect(model_name: str, part_name: str, effect_id: int): + led_map = state.led_map + delete_name = next( + name + for name, effect in led_map[model_name][part_name].items() + if effect.id == effect_id + ) + del led_map[model_name][part_name][delete_name] + set_led_map(led_map) + + +def apply_led_map_updates(): + set_ctrl_keyframes_from_state(effect_only=True) + state.led_map_pending = False diff --git a/editor-blender/core/models/__init__.py b/editor-blender/core/models/__init__.py index cd0d3b2bd..05a7d2d4f 100644 --- a/editor-blender/core/models/__init__.py +++ b/editor-blender/core/models/__init__.py @@ -26,7 +26,7 @@ class Color: @dataclass -class LEDBuldData: +class LEDBulbData: color_id: ColorID alpha: int rgb: Optional[RGB] = None # for calculating fade @@ -36,7 +36,7 @@ class LEDBuldData: class LEDEffect: id: LEDEffectID name: LEDEffectName - effect: List[LEDBuldData] + effect: List[LEDBulbData] LEDEffectIDTable = Dict[LEDEffectID, LEDEffect] @@ -361,3 +361,5 @@ class State: pos_map_updates: PosMapUpdates pos_map_pending: bool + + led_map_pending: bool diff --git a/editor-blender/core/states/__init__.py b/editor-blender/core/states/__init__.py index 90b367fd6..4bb2c9d00 100644 --- a/editor-blender/core/states/__init__.py +++ b/editor-blender/core/states/__init__.py @@ -83,4 +83,5 @@ control_map_pending=False, pos_map_updates=PosMapUpdates(added=[], updated=[], deleted=[]), pos_map_pending=False, + led_map_pending=False, ) diff --git a/editor-blender/core/utils/convert.py b/editor-blender/core/utils/convert.py index 3d7f010c2..a160194b8 100644 --- a/editor-blender/core/utils/convert.py +++ b/editor-blender/core/utils/convert.py @@ -22,6 +22,7 @@ from ...graphqls.subscriptions import ( SubControlFrame, SubEffectListItemData, + SubLEDRecordDataItem, SubPositionFrame, ) from ..models import ( @@ -36,7 +37,7 @@ DancersArrayPartsItem, DancerStatus, FiberData, - LEDBuldData, + LEDBulbData, LEDData, LEDEffect, LEDEffectID, @@ -260,7 +261,7 @@ def led_map_query_to_state(payload: QueryLEDMapPayload) -> LEDMap: for effect_name, effect in effects.items(): frame = effect.frames[0] bulb_data = [ - LEDBuldData(color_id=color_id, alpha=alpha) + LEDBulbData(color_id=color_id, alpha=alpha) for color_id, alpha in frame.LEDs ] part_map[effect_name] = LEDEffect( @@ -295,6 +296,14 @@ def effect_list_data_sub_to_query(data: SubEffectListItemData) -> QueryEffectLis return effectListItem +def led_record_sub_to_state_item(led_payload_item: SubLEDRecordDataItem) -> LEDEffect: + effect = [ + LEDBulbData(color_id=bulb[0], alpha=bulb[1]) + for bulb in led_payload_item.frames[0].LEDs + ] + return LEDEffect(id=led_payload_item.id, name=led_payload_item.name, effect=effect) + + def rgb_to_float(rgb: Tuple[int, ...]) -> Tuple[float, ...]: return tuple([color / 255 for color in rgb]) diff --git a/editor-blender/graphqls/mutations.py b/editor-blender/graphqls/mutations.py index c5294c766..c8439c189 100644 --- a/editor-blender/graphqls/mutations.py +++ b/editor-blender/graphqls/mutations.py @@ -479,6 +479,42 @@ class MutAddLEDEffectInput(JSONWizard): """ +@dataclass +class MutRequestEditLEDEffectResponse(JSONWizard): + ok: bool + editing: Optional[MapID] = None + + +REQUEST_EDIT_LED_EFFECT_BY_ID = gql( + """ + mutation RequestEditLEDEffect($ledEffectId: Int!) { + RequestEditLEDEffect(ledEffectId: $ledEffectId) { + editing + ok + } + } + """ +) + + +@dataclass +class MutCancelEditLEDEffectResponse(JSONWizard): + ok: bool + editing: Optional[MapID] = None + + +CANCEL_EDIT_LED_EFFECT_BY_ID = gql( + """ + mutation CancelEditLEDEffect($ledEffectId: Int!) { + CancelEditLEDEffect(ledEffectId: $ledEffectId) { + editing + ok + } + } + """ +) + + @dataclass class MutEditLEDEffectResponse(JSONWizard): ok: bool diff --git a/editor-blender/graphqls/subscriptions.py b/editor-blender/graphqls/subscriptions.py index eb21b9896..fb3d963c7 100644 --- a/editor-blender/graphqls/subscriptions.py +++ b/editor-blender/graphqls/subscriptions.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from enum import Enum -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Dict, List, Optional, Tuple, Union from dataclass_wizard import JSONWizard from gql import gql @@ -243,6 +243,64 @@ class SubEffectListData(JSONWizard): ) +@dataclass +class SubLEDRecordDataBulbData(JSONWizard): + LEDs: List[Tuple[int, int]] + + +@dataclass +class SubLEDRecordDataItem(JSONWizard): + id: int + name: str + model_name: str + part_name: str + frames: List[SubLEDRecordDataBulbData] + + +@dataclass +class SubLEDRecordData(JSONWizard): + createEffects: List[SubLEDRecordDataItem] + updateEffects: List[SubLEDRecordDataItem] + deleteEffects: List[SubLEDRecordDataItem] + + +SUB_LED_RECORD = gql( + """ + subscription ledRecordSubscription { + ledRecordSubscription { + createEffects { + id + name + modelName + partName + frames { + LEDs + } + } + updateEffects { + id + name + modelName + partName + frames { + LEDs + } + } + deleteEffects { + id + name + modelName + partName + frames { + LEDs + } + } + } + } + """ +) + + """ Color """ diff --git a/editor-blender/operators/editor/__init__.py b/editor-blender/operators/editor/__init__.py index 1157c5768..404d3e04a 100644 --- a/editor-blender/operators/editor/__init__.py +++ b/editor-blender/operators/editor/__init__.py @@ -11,11 +11,13 @@ from ...core.actions.state.control_map import apply_control_map_updates from ...core.actions.state.editor import set_editor from ...core.actions.state.led_editor import ( + add_led_effect, cancel_edit_led_effect, delete_led_effect, request_edit_led_effect, save_led_effect, ) +from ...core.actions.state.led_map import apply_led_map_updates from ...core.actions.state.pos_editor import ( add_pos_frame, cancel_edit_pos, @@ -103,6 +105,7 @@ def poll(cls, context: bpy.types.Context): state.color_map_pending or state.control_map_pending or state.pos_map_pending + or state.led_map_pending ) def execute(self, context: bpy.types.Context): @@ -112,6 +115,8 @@ def execute(self, context: bpy.types.Context): apply_pos_map_updates() if state.color_map_pending: apply_color_map_updates() + if state.led_map_pending: + apply_led_map_updates() notify("INFO", "Synced pending updates") @@ -169,7 +174,7 @@ async def async_execute(self, context: bpy.types.Context): case Editor.POS_EDITOR: await add_pos_frame() case Editor.LED_EDITOR: - pass + await add_led_effect() class Save(AsyncOperator): diff --git a/editor-blender/panels/led_editor/__init__.py b/editor-blender/panels/led_editor/__init__.py index 50cfc8caf..d62e91864 100644 --- a/editor-blender/panels/led_editor/__init__.py +++ b/editor-blender/panels/led_editor/__init__.py @@ -32,42 +32,46 @@ def draw(self, context: bpy.types.Context): edit_mode = ld_ui_led_editor.edit_mode - if edit_mode == LEDEditorEditModeType.IDLE.value: - row = layout.row() - row.prop(ld_ui_led_editor, "edit_model", text="Model") - - row = layout.row() - row.prop(ld_ui_led_editor, "edit_dancer", text="Dancer") - - row = layout.row() - row.prop(ld_ui_led_editor, "edit_part", text="Part") - - row = layout.row() - row.prop(ld_ui_led_editor, "edit_effect", text="Effect") - - elif edit_mode == LEDEditorEditModeType.EDIT.value: - # TODO: Show part info - - # show properties of light - column = layout.column() - - if ld_ui_led_editor.multi_select: - column.prop(ld_ui_led_editor, "multi_select_color", text="Color") - else: - # check if object is selected - obj = context.object - if obj is None: # type: ignore - return - - ld_object_type: str = getattr(obj, "ld_object_type") - ld_light_type: str = getattr(obj, "ld_light_type") - if ( - ld_object_type != ObjectType.LIGHT.value - or ld_light_type != LightType.LED_BULB.value - ): - return - - column.prop(obj, "ld_color", text="Color") + match edit_mode: + case LEDEditorEditModeType.IDLE.value: + row = layout.row() + row.prop(ld_ui_led_editor, "edit_model", text="Model") + + row = layout.row() + row.prop(ld_ui_led_editor, "edit_dancer", text="Dancer") + + row = layout.row() + row.prop(ld_ui_led_editor, "edit_part", text="Part") + + row = layout.row() + row.prop(ld_ui_led_editor, "edit_effect", text="Effect") + pass + case LEDEditorEditModeType.EDIT.value: + # TODO: Show part info + + # show properties of light + column = layout.column() + + if ld_ui_led_editor.multi_select: + column.prop(ld_ui_led_editor, "multi_select_color", text="Color") + else: + # check if object is selected + obj = context.object + if obj is None: # type: ignore + return + + ld_object_type: str = getattr(obj, "ld_object_type") + ld_light_type: str = getattr(obj, "ld_light_type") + if ( + ld_object_type != ObjectType.LIGHT.value + or ld_light_type != LightType.LED_BULB.value + ): + return + + column.prop(obj, "ld_color", text="Color") + case LEDEditorEditModeType.NEW.value: + column = layout.column() + column.prop(ld_ui_led_editor, "new_effect", text="Name") def register(): diff --git a/editor-blender/properties/ui/led_editor.py b/editor-blender/properties/ui/led_editor.py index 47fc077ff..bb0c2db19 100644 --- a/editor-blender/properties/ui/led_editor.py +++ b/editor-blender/properties/ui/led_editor.py @@ -4,6 +4,7 @@ from ...core.actions.property.led_editor import ( update_edit_dancer, + update_edit_effect, update_edit_model, update_edit_part, update_multi_select_color, @@ -169,9 +170,9 @@ class LEDEditorStatus(bpy.types.PropertyGroup): set=set_edit_part, ) edit_effect: bpy.props.EnumProperty( # type: ignore - items=get_effect_lists, - default=-1, # pyright: ignore + items=get_effect_lists, default=-1, update=update_edit_effect # pyright: ignore ) + new_effect: bpy.props.StringProperty(default="New effect") # type: ignore multi_select: bpy.props.BoolProperty( # type: ignore name="Multi Select", diff --git a/editor-blender/properties/ui/types.py b/editor-blender/properties/ui/types.py index 499452e31..5cc03faa3 100644 --- a/editor-blender/properties/ui/types.py +++ b/editor-blender/properties/ui/types.py @@ -46,6 +46,7 @@ class LEDEditorStatusType: edit_dancer: str edit_part: str edit_effect: str + new_effect: str multi_select: bool multi_select_color: str diff --git a/editor-server/src/graphql/mutations/led.rs b/editor-server/src/graphql/mutations/led.rs index 8e54d2a54..b4d0624f8 100644 --- a/editor-server/src/graphql/mutations/led.rs +++ b/editor-server/src/graphql/mutations/led.rs @@ -405,17 +405,23 @@ impl LEDMutation { let mysql = clients.mysql_pool(); // check if effect exists - let led_effect = sqlx::query!( + let led_effect = match sqlx::query!( r#" - SELECT * FROM LEDEffect WHERE id = ?; + SELECT + LEDEffect.*, + Model.name as "model_name", + Part.name as "part_name" + FROM LEDEffect + INNER JOIN Model ON LEDEffect.model_id = Model.id + INNER JOIN Part ON LEDEffect.part_id = Part.id + WHERE LEDEffect.id = ?; "#, id ) - .fetch_optional(mysql) - .await; - - match led_effect { - Ok(_) => {} + .fetch_one(mysql) + .await + { + Ok(led_effect) => led_effect, Err(_) => { return Ok(DeleteLEDEffectResponse { ok: false, @@ -495,7 +501,14 @@ impl LEDMutation { let led_payload = LEDPayload { create_effects: Vec::new(), update_effects: Vec::new(), - delete_effects: vec![id], + delete_effects: vec![LEDEffectData { + id, + name: "".to_string(), + model_name: led_effect.model_name.clone(), + part_name: led_effect.part_name.clone(), + repeat: 0, + frames: vec![], + }], }; Subscriptor::publish(led_payload); diff --git a/editor-server/src/graphql/subscriptions/led.rs b/editor-server/src/graphql/subscriptions/led.rs index 5bfe25872..b2aac4503 100644 --- a/editor-server/src/graphql/subscriptions/led.rs +++ b/editor-server/src/graphql/subscriptions/led.rs @@ -9,7 +9,7 @@ use futures_core::stream::Stream; pub struct LEDPayload { pub create_effects: Vec, pub update_effects: Vec, - pub delete_effects: Vec, + pub delete_effects: Vec, } #[derive(Default)]