diff --git a/Test1.json b/Test1.json new file mode 100644 index 0000000..b8f0064 --- /dev/null +++ b/Test1.json @@ -0,0 +1,576 @@ +{ + "id": "c2600a8d-8eee-4d7f-a41a-8106b9c8e62a", + "name": "New Synoptik", + "description": "", + "machines": [ + { + "id": "977ef95a-42db-4b36-a3e6-45e11b3ae554", + "name": "Moniteur", + "category": "Affichage", + "manufacturer": "Générique", + "model": "Display", + "inputs": [ + { + "id": "b7c8b4be-e257-4eeb-ac49-ae0d19e2783c", + "name": "HDMI IN", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "input", + "machine_id": "977ef95a-42db-4b36-a3e6-45e11b3ae554", + "index": 0 + } + ], + "outputs": [], + "position": [ + 482, + 118 + ], + "size": null, + "color": "#43A047", + "description": "", + "notes": "" + }, + { + "id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "name": "ATEM Mini", + "category": "Mélangeur", + "manufacturer": "Blackmagic", + "model": "ATEM Mini", + "inputs": [ + { + "id": "9ba74a6e-eed7-4e9a-8ff5-3ac3a50b805a", + "name": "HDMI 1", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "input", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 0 + }, + { + "id": "fa75c842-6730-40ac-be5c-f0e8c0b7a207", + "name": "HDMI 2", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "input", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 1 + }, + { + "id": "f7952365-bef5-446b-ac16-10453fc4e9fa", + "name": "HDMI 3", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "input", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 2 + }, + { + "id": "2fde6463-891b-4d0f-81c3-9a5835dbd6ca", + "name": "HDMI 4", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "input", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 3 + }, + { + "id": "37c81250-7310-4665-b9f0-2240f7b62746", + "name": "MIC 1", + "flux_type": { + "id": "208d9829-8377-42ba-b029-f5b2dae773ab", + "name": "Mini-Jack", + "category_id": "audio", + "color": "#CDDC39", + "description": "Jack 3.5mm", + "connector_type": "Jack 3.5", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 4 + }, + { + "id": "5a34ebc9-7159-4059-bf5a-53bde3a9a92c", + "name": "MIC 2", + "flux_type": { + "id": "208d9829-8377-42ba-b029-f5b2dae773ab", + "name": "Mini-Jack", + "category_id": "audio", + "color": "#CDDC39", + "description": "Jack 3.5mm", + "connector_type": "Jack 3.5", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 5 + } + ], + "outputs": [ + { + "id": "42120229-c28b-4b8a-ad07-866abadcf543", + "name": "HDMI OUT", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "output", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 0 + }, + { + "id": "12074e22-b46c-44c5-8f6d-9ebf22135bd6", + "name": "USB-C", + "flux_type": { + "id": "82ba792c-cd4b-4f72-8e7a-cd5e7ee40a60", + "name": "USB-C", + "category_id": "data", + "color": "#1976D2", + "description": "USB Type C", + "connector_type": "USB-C", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "output", + "machine_id": "92b310b6-30c2-4ce7-bacd-8b58fc7d3828", + "index": 1 + } + ], + "position": [ + 180, + 130 + ], + "size": null, + "color": "#7B1FA2", + "description": "", + "notes": "" + }, + { + "id": "7c9eb69c-5ba0-40b4-8236-fc51bed5816d", + "name": "Computer", + "category": "Other", + "manufacturer": "", + "model": "", + "inputs": [ + { + "id": "1f47595c-6d7b-432c-b1d6-23a51841a9c9", + "name": "Power 19V", + "flux_type": { + "id": "5a1458ba-39eb-45b9-9a54-b1b3bab7e5f0", + "name": "AC Power", + "category_id": "power", + "color": "#F44336", + "description": "Alimentation secteur", + "connector_type": "IEC C13/C14", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "7c9eb69c-5ba0-40b4-8236-fc51bed5816d", + "index": 0 + }, + { + "id": "d511b4d2-1d4c-4136-a477-be049c754251", + "name": "Thunderbolt", + "flux_type": { + "id": "1fcaba72-4f84-4b89-bd71-ac035fb25410", + "name": "Thunderbolt", + "category_id": "data", + "color": "#0D47A1", + "description": "Thunderbolt", + "connector_type": "USB-C/TB", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "input", + "machine_id": "7c9eb69c-5ba0-40b4-8236-fc51bed5816d", + "index": 1 + } + ], + "outputs": [ + { + "id": "be40fa42-a59b-4c96-9e7a-07648e32c569", + "name": "Video Out", + "flux_type": { + "id": "6ff480b3-ac5e-4cc0-b57a-57fdff8d2074", + "name": "HDMI", + "category_id": "video", + "color": "#E91E63", + "description": "High-Definition Multimedia Interface", + "connector_type": "HDMI Type A", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "output", + "machine_id": "7c9eb69c-5ba0-40b4-8236-fc51bed5816d", + "index": 0 + }, + { + "id": "cc1c4377-2728-4990-b88b-d05c0759bc07", + "name": "Audio Out", + "flux_type": { + "id": "208d9829-8377-42ba-b029-f5b2dae773ab", + "name": "Mini-Jack", + "category_id": "audio", + "color": "#CDDC39", + "description": "Jack 3.5mm", + "connector_type": "Jack 3.5", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "output", + "machine_id": "7c9eb69c-5ba0-40b4-8236-fc51bed5816d", + "index": 1 + }, + { + "id": "ade49023-865a-40a5-b2e8-c3cc7dc53f13", + "name": "USB C", + "flux_type": { + "id": "82ba792c-cd4b-4f72-8e7a-cd5e7ee40a60", + "name": "USB-C", + "category_id": "data", + "color": "#1976D2", + "description": "USB Type C", + "connector_type": "USB-C", + "signal_type": "digital", + "bidirectional": false + }, + "direction": "output", + "machine_id": "7c9eb69c-5ba0-40b4-8236-fc51bed5816d", + "index": 2 + } + ], + "position": [ + 106, + 405 + ], + "size": null, + "color": "#b65c5c", + "description": "", + "notes": "" + }, + { + "id": "fb546022-cc29-4de7-80f7-fb8f4132cee1", + "name": "Convertisseur mini-jack XLR F x2", + "category": "Source", + "manufacturer": "", + "model": "", + "inputs": [ + { + "id": "a6ce0b54-b36f-4b74-9ad5-fa29af6cde0e", + "name": "mini-jack M", + "flux_type": { + "id": "208d9829-8377-42ba-b029-f5b2dae773ab", + "name": "Mini-Jack", + "category_id": "audio", + "color": "#CDDC39", + "description": "Jack 3.5mm", + "connector_type": "Jack 3.5", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "fb546022-cc29-4de7-80f7-fb8f4132cee1", + "index": 0 + } + ], + "outputs": [ + { + "id": "d1eafcfa-fbc9-4d0d-a42d-f8023de2732b", + "name": "XLR M", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "output", + "machine_id": "fb546022-cc29-4de7-80f7-fb8f4132cee1", + "index": 0 + }, + { + "id": "eb343957-e039-4207-a561-0e9b35b56706", + "name": "XLR F", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "output", + "machine_id": "fb546022-cc29-4de7-80f7-fb8f4132cee1", + "index": 1 + } + ], + "position": [ + 295, + 475 + ], + "size": null, + "color": "#2d2d2d", + "description": "", + "notes": "" + }, + { + "id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "name": "Console Audio", + "category": "Audio", + "manufacturer": "Générique", + "model": "Mixer 8CH", + "inputs": [ + { + "id": "c09a0980-5912-4f4f-9119-1438d33d4ef3", + "name": "XLR 1", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 0 + }, + { + "id": "d527d52a-fa9e-4636-86f8-c8d542504ad2", + "name": "XLR 2", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 1 + }, + { + "id": "309bd756-e11d-4e78-b422-ad0493e493af", + "name": "XLR 3", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 2 + }, + { + "id": "5e86f501-c332-43d5-a798-4026e86138eb", + "name": "XLR 4", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 3 + }, + { + "id": "db7c2b04-8218-4249-bcb8-d53d47c53874", + "name": "LINE 5", + "flux_type": { + "id": "087e6684-ced6-4988-9e75-20987e62f23e", + "name": "Jack 6.35", + "category_id": "audio", + "color": "#8BC34A", + "description": "Jack 6.35mm TRS", + "connector_type": "Jack 6.35", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 4 + }, + { + "id": "508d0179-1db9-4497-a322-49b19da9e4f4", + "name": "LINE 6", + "flux_type": { + "id": "087e6684-ced6-4988-9e75-20987e62f23e", + "name": "Jack 6.35", + "category_id": "audio", + "color": "#8BC34A", + "description": "Jack 6.35mm TRS", + "connector_type": "Jack 6.35", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "input", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 5 + } + ], + "outputs": [ + { + "id": "c96530da-3f03-407f-a5fd-04554adec3a0", + "name": "MAIN L", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "output", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 0 + }, + { + "id": "1f796e4b-2b49-475f-807b-a4323807702f", + "name": "MAIN R", + "flux_type": { + "id": "c30669a9-da43-4eb0-a2d0-8be4a093a803", + "name": "XLR", + "category_id": "audio", + "color": "#4CAF50", + "description": "XLR Audio Connector", + "connector_type": "XLR 3-pin", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "output", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 1 + }, + { + "id": "cc122298-c1c2-4bb5-8c5b-06689260ec42", + "name": "AUX 1", + "flux_type": { + "id": "087e6684-ced6-4988-9e75-20987e62f23e", + "name": "Jack 6.35", + "category_id": "audio", + "color": "#8BC34A", + "description": "Jack 6.35mm TRS", + "connector_type": "Jack 6.35", + "signal_type": "analog", + "bidirectional": false + }, + "direction": "output", + "machine_id": "708a37ab-e7a3-4914-a33c-79622125a2d9", + "index": 2 + } + ], + "position": [ + 621, + 517 + ], + "size": null, + "color": "#00897B", + "description": "", + "notes": "" + } + ], + "connections": [ + { + "id": "3f724852-0c6b-4431-925a-71f55164b216", + "source_port_id": "42120229-c28b-4b8a-ad07-866abadcf543", + "target_port_id": "b7c8b4be-e257-4eeb-ac49-ae0d19e2783c", + "label": "", + "color": null + }, + { + "id": "ab2a63fb-d6e6-4ce4-82f5-56c5b5f30d84", + "source_port_id": "cc1c4377-2728-4990-b88b-d05c0759bc07", + "target_port_id": "a6ce0b54-b36f-4b74-9ad5-fa29af6cde0e", + "label": "", + "color": null + }, + { + "id": "bb8c9546-c159-4f8c-bd40-abe062e252bd", + "source_port_id": "d1eafcfa-fbc9-4d0d-a42d-f8023de2732b", + "target_port_id": "c09a0980-5912-4f4f-9119-1438d33d4ef3", + "label": "", + "color": null + }, + { + "id": "6a6edeb5-c54e-417b-b520-028079ee0521", + "source_port_id": "eb343957-e039-4207-a561-0e9b35b56706", + "target_port_id": "d527d52a-fa9e-4636-86f8-c8d542504ad2", + "label": "", + "color": null + } + ], + "custom_flux_types": [], + "created_at": "2026-01-11T22:45:46.506865", + "modified_at": "2026-01-11T22:51:58.198843" +} \ No newline at end of file diff --git a/synodetik/gui/components/node_editor.py b/synodetik/gui/components/node_editor.py index a97ac19..4b13bba 100644 --- a/synodetik/gui/components/node_editor.py +++ b/synodetik/gui/components/node_editor.py @@ -264,6 +264,14 @@ class NodeEditorPanel: """Get port ID from attribute tag.""" return self._attr_to_port.get(attr_tag) + def get_link_tag(self, connection_id: str) -> Optional[str]: + """Get DPG link tag for a connection ID.""" + return self._conn_to_link.get(connection_id) + + def get_attr_tag(self, port_id: str) -> Optional[str]: + """Get DPG attribute tag for a port ID.""" + return self._port_to_attr.get(port_id) + def _create_port_attribute(self, port, is_input: bool) -> str: """Create a node attribute for a port.""" flux_color = hex_to_rgba(port.flux_type.color) diff --git a/synodetik/modules/builtins/colored_links.py b/synodetik/modules/builtins/colored_links.py new file mode 100644 index 0000000..b0de0da --- /dev/null +++ b/synodetik/modules/builtins/colored_links.py @@ -0,0 +1,144 @@ +""" +Colored Links Module - Colorize connections based on flux type. + +This module automatically applies the flux type color to connection links +in the node editor, making it easier to visually identify signal types. +""" +import dearpygui.dearpygui as dpg + +from synodetik.modules import Module, ModuleInfo +from synodetik.events import EventType +from synodetik.gui.themes import hex_to_rgba + + +class ColoredLinksModule(Module): + """ + Colorizes node editor links based on flux type color. + + When a connection is created, this module automatically applies + the source port's flux type color to the link, providing visual + consistency between port colors and connection colors. + """ + + def __init__(self): + super().__init__() + # Track created themes for cleanup + self._link_themes: dict[str, int] = {} + + @property + def info(self) -> ModuleInfo: + return ModuleInfo( + id="colored_links", + name="Colored Links", + version="1.0.0", + author="Synodetik", + description="Colorize connections based on flux type" + ) + + def on_load(self) -> bool: + """Subscribe to connection events.""" + self.events.on(EventType.CONNECTION_CREATED, self._on_connection_created) + self.events.on(EventType.SYNOPTIK_LOADED, self._on_synoptik_loaded) + + # Colorize any existing connections + self._colorize_all_connections() + + print(f"[{self.info.name}] Module loaded") + return True + + def on_unload(self) -> None: + """Unsubscribe and clean up themes.""" + self.events.off(EventType.CONNECTION_CREATED, self._on_connection_created) + self.events.off(EventType.SYNOPTIK_LOADED, self._on_synoptik_loaded) + + # Clean up all created themes + for theme_id in self._link_themes.values(): + if dpg.does_item_exist(theme_id): + dpg.delete_item(theme_id) + self._link_themes.clear() + + print(f"[{self.info.name}] Module unloaded") + + def _on_connection_created(self, event) -> None: + """Handle new connection creation.""" + connection = event.data.get('connection') + if connection: + self._colorize_link(connection) + + def _on_synoptik_loaded(self, event) -> None: + """Handle synoptik load - colorize all connections.""" + # Small delay to ensure UI is ready + self._colorize_all_connections() + + def _colorize_all_connections(self) -> None: + """Colorize all existing connections in the current synoptik.""" + if not self.app or not self.app.synoptik: + return + + for connection in self.app.synoptik.connections: + self._colorize_link(connection) + + def _colorize_link(self, connection) -> None: + """Apply flux color to a connection link.""" + if not self.app or not self.app.synoptik or not self.app.node_editor: + return + + # Get the source port to determine flux color + source_port = self.app.synoptik._find_port(connection.source_port_id) + if not source_port: + return + + # Get flux color + flux_color = source_port.flux_type.color + + # Get the DPG link tag + link_tag = self.app.node_editor.get_link_tag(connection.id) + if not link_tag or not dpg.does_item_exist(link_tag): + return + + # Create and apply theme + theme = self._create_link_theme(connection.id, flux_color) + dpg.bind_item_theme(link_tag, theme) + + def _create_link_theme(self, connection_id: str, color: str) -> int: + """Create a DPG theme for a colored link.""" + # Clean up existing theme for this connection if any + if connection_id in self._link_themes: + old_theme = self._link_themes[connection_id] + if dpg.does_item_exist(old_theme): + dpg.delete_item(old_theme) + + # Convert hex color to RGBA + rgba = hex_to_rgba(color) + + # Create theme with link colors + with dpg.theme() as link_theme: + with dpg.theme_component(dpg.mvNodeLink): + dpg.add_theme_color( + dpg.mvNodeCol_Link, + rgba, + category=dpg.mvThemeCat_Nodes + ) + dpg.add_theme_color( + dpg.mvNodeCol_LinkHovered, + self._brighten_color(rgba, 1.3), + category=dpg.mvThemeCat_Nodes + ) + dpg.add_theme_color( + dpg.mvNodeCol_LinkSelected, + self._brighten_color(rgba, 1.5), + category=dpg.mvThemeCat_Nodes + ) + + self._link_themes[connection_id] = link_theme + return link_theme + + def _brighten_color(self, rgba: tuple, factor: float) -> tuple: + """Brighten a color by a factor.""" + r, g, b, a = rgba + return ( + min(255, int(r * factor)), + min(255, int(g * factor)), + min(255, int(b * factor)), + a + )