custom joint support

This commit is contained in:
2026-05-04 16:43:32 -07:00
parent 67243649ef
commit 17789a7615
2 changed files with 93 additions and 5 deletions
+89 -3
View File
@@ -37,7 +37,7 @@ import PySide6
from PySide6.QtWidgets import (QApplication, QDoubleSpinBox, QFormLayout, QGraphicsItem, QGraphicsProxyWidget, QGraphicsTextItem, QLineEdit, QListWidget, QListWidgetItem, QMainWindow, QProgressDialog, QSizePolicy, QStyleOptionGraphicsItem, QTabBar, QWidget, QVBoxLayout, QGraphicsView, QGraphicsScene,
QHBoxLayout, QSplitter, QLabel, QPushButton, QComboBox, QInputDialog, QGraphicsRectItem,
QFileDialog, QScrollArea, QMessageBox, QSlider, QTextEdit, QGroupBox, QGridLayout, QCheckBox, QTabWidget, QProgressBar)
from PySide6.QtCore import QEvent, Qt, QThread, Signal, QUrl, QRectF, QPointF, QRect, QSizeF, QTimer
from PySide6.QtCore import QEvent, QObject, Qt, QThread, Signal, QUrl, QRectF, QPointF, QRect, QSizeF, QTimer
from PySide6.QtGui import QCursor, QDoubleValidator, QGuiApplication, QPainter, QColor, QFont, QPen, QBrush, QAction, QKeySequence, QIcon, QTextOption, QImage, QPixmap, QTransform
from PySide6.QtMultimedia import QMediaPlayer, QAudioOutput
from PySide6.QtMultimediaWidgets import QGraphicsVideoItem
@@ -3162,10 +3162,17 @@ from PySide6.QtWidgets import QGraphicsPathItem, QGraphicsSimpleTextItem
from PySide6.QtWidgets import QGraphicsItem, QGraphicsSimpleTextItem, QInputDialog
class BlockSignalProxy(QObject):
nameChanged = Signal(str, str)
class PuzzleBlock(QGraphicsPathItem):
def __init__(self, b_type, label, parent_item=None, fields=None):
super().__init__(parent_item)
self.signals = BlockSignalProxy()
self.b_type = b_type # "begin", "middle", "end"
self.label_text = label
self.width = 160
@@ -3322,8 +3329,7 @@ class PuzzleBlock(QGraphicsPathItem):
if self.b_type == "begin":
new_name, ok = QInputDialog.getText(None, "Rename Step", "Enter name:", text=self.label_text)
if ok and new_name:
self.label_text = new_name
self.label_item.setText(new_name)
self.finish_rename(new_name)
super().mouseDoubleClickEvent(event)
@@ -3383,6 +3389,20 @@ class PuzzleBlock(QGraphicsPathItem):
return super().itemChange(change, value)
def finish_rename(self, new_text):
old_text = self.label_text
print(f"[DEBUG - Block] Renaming '{old_text}' to '{new_text}'")
self.label_text = new_text
if hasattr(self, 'label_item'):
self.label_item.setText(new_text)
self.update()
if self.b_type == "begin":
print(f"[DEBUG - Block] Emitting nameChanged signal...")
self.signals.nameChanged.emit(old_text, new_text)
class BlockLibrary(QListWidget):
def __init__(self, parent_tab, stringy):
@@ -3447,8 +3467,39 @@ class BlockLibrary(QListWidget):
print(f"DEBUG: Drag finished with result: {result}")
def add_dynamic_logic_item(self, block_item):
"""
Triggered when a 'begin' block is dropped on the canvas.
Adds a corresponding 'logic' block to this library.
"""
# 1. Check for duplicates
# We don't want to add "Joint 1" five times if they drag five 'begin' blocks
label = block_item.label_text
items = self.findItems(label, Qt.MatchExactly)
for item in items:
if item.data(Qt.UserRole) == "logic":
print(f"DEBUG: {label} (logic) already exists in library. Skipping.")
return
# 2. Add the item as a 'logic' type
# In your system, logic blocks have no fields (they are just variables)
print(f"DEBUG: Dynamically adding '{label}' as a logic block.")
self.add_item(label, "logic", fields=[])
def update_item_name(self, old_name, new_name):
print(f"[DEBUG - Library] Searching for items matching: '{old_name}'")
items = self.findItems(old_name, Qt.MatchExactly)
if not items:
print(f"[DEBUG - Library] No items found matching '{old_name}'")
for item in items:
# Ensure we only rename the logic-type items
if item.data(Qt.UserRole) == "logic":
item.setText(new_name)
print(f"[DEBUG - Library] Successfully updated sidebar item to '{new_name}'")
from PySide6.QtWidgets import QGraphicsLineItem, QGraphicsRectItem, QGraphicsSimpleTextItem
@@ -3456,12 +3507,40 @@ from PySide6.QtGui import QPen, QColor, QBrush
class TopologyCanvas(QGraphicsView):
beginBlockDropped = Signal(object)
def __init__(self):
self.scene = QGraphicsScene()
super().__init__(self.scene)
self.setAcceptDrops(True)
self.block_library_ref = None
self.scene.setSceneRect(0, 0, 2000, 2000)
self.beginBlockDropped.connect(self.on_new_definition_created)
def on_new_definition_created(self, block_item):
# Connect the block's rename signal to our canvas sync method
print(f"[DEBUG - Canvas] Connecting signal for new block: {block_item.label_text}")
block_item.signals.nameChanged.connect(self.sync_logic_blocks)
def sync_logic_blocks(self, old_name, new_name):
print(f"[DEBUG - Canvas] Syncing. Old: {old_name}, New: {new_name}")
# 1. Update existing blocks on canvas (This is already working!)
for item in self.scene.items():
if isinstance(item, PuzzleBlock) and item.b_type == "logic":
if item.label_text == old_name:
item.label_text = new_name
if hasattr(item, 'label_item'):
item.label_item.setText(new_name)
item.update()
# 2. Update Sidebar using the direct reference
if self.block_library_ref:
print("[DEBUG - Canvas] Found block_library_ref. Calling update...")
self.block_library_ref.update_item_name(old_name, new_name)
else:
print("[DEBUG - Canvas] ERROR: block_library_ref is None. Ensure it is linked in main.py.")
def mousePressEvent(self, event):
@@ -3546,6 +3625,9 @@ class TopologyCanvas(QGraphicsView):
if not self.perform_snap(new_block, self.mapToScene(event.position().toPoint())):
new_block.setPos(self.mapToScene(event.position().toPoint()))
if block_type == "begin":
self.beginBlockDropped.emit(new_block)
event.acceptProposedAction()
@@ -3958,6 +4040,10 @@ class ModelParameterConfigurationTab(QWidget):
sidebar_layout = QVBoxLayout(sidebar_container)
self.block_library = BlockLibrary(parent_tab=self, stringy=self.mode)
self.canvas.block_library_ref = self.block_library
self.canvas.beginBlockDropped.connect(self.block_library.add_dynamic_logic_item)
# Reuse your existing Inspector logic
self.inspector_scroll = QScrollArea()