# backend/resolvers.py import pcbnew def get_item_uuid(item): """ Robustly retrieve the UUID string from a KiCad item. Prioritizes m_Uuid property (KiCad 9 SWIG) over GetKIID(). """ if not item: return None try: # KiCad 9 / SWIG property access if hasattr(item, 'm_Uuid'): return item.m_Uuid.AsString() # Legacy / Alternative accessor if hasattr(item, 'GetKIID'): return item.GetKIID().AsString() except: pass return None def resolve_to_trackable_item(item): """ Resolves an item to the actual object we want to track. - If item is a Pad/Text/Shape inside a Footprint -> Returns the Footprint. - If item is a Group -> Returns None (we track contents, not groups). - Otherwise -> Returns the item itself. """ if not item: return None cls = item.GetClass() if cls == "PCB_GROUP": return None # Check for Parent (e.g. Pad -> Footprint) parent = item.GetParent() if parent and parent.GetClass() == "FOOTPRINT": return parent return item def cast_item(item): """ Casts a generic BOARD_ITEM to its specific class type. Required for methods like Serialize or Format to work correctly. """ if not item: return None # Try generic Cast() first (Available on some BOARD_ITEM wrappers) if hasattr(item, 'Cast'): try: return item.Cast() except: pass # Fallback to manual casting based on class name cls = item.GetClass() try: if cls == "FOOTPRINT": return pcbnew.Cast_to_FOOTPRINT(item) if cls == "PCB_TRACK": return pcbnew.Cast_to_PCB_TRACK(item) if cls == "PCB_VIA": return pcbnew.Cast_to_PCB_VIA(item) if cls == "PCB_ARC": return pcbnew.Cast_to_PCB_ARC(item) if cls == "PCB_SHAPE": return pcbnew.Cast_to_PCB_SHAPE(item) if cls == "PCB_TEXT": return pcbnew.Cast_to_PCB_TEXT(item) if cls == "PCB_TEXTBOX": return pcbnew.Cast_to_PCB_TEXTBOX(item) if cls == "ZONE": return pcbnew.Cast_to_ZONE(item) if cls == "PCB_GROUP": return pcbnew.Cast_to_PCB_GROUP(item) if cls == "PCB_TARGET": return pcbnew.Cast_to_PCB_TARGET(item) if cls == "PCB_DIM_ALIGNED": return pcbnew.Cast_to_PCB_DIM_ALIGNED(item) if cls == "PCB_DIM_ORTHOGONAL": return pcbnew.Cast_to_PCB_DIM_ORTHOGONAL(item) if cls == "PCB_DIM_CENTER": return pcbnew.Cast_to_PCB_DIM_CENTER(item) if cls == "PCB_DIM_LEADER": return pcbnew.Cast_to_PCB_DIM_LEADER(item) if cls == "PCB_DIM_RADIAL": return pcbnew.Cast_to_PCB_DIM_RADIAL(item) except: pass return item def find_item_by_uuid(board, uuid): """ Locates an item on the board by its UUID string. Checks standard lists (Tracks, Footprints, Drawings, Zones). Returns a CAST item (specific type) if found. """ item = None if hasattr(board, 'GetItem'): try: item = board.GetItem(pcbnew.KIID(uuid)) except: pass if not item: # Fallback lists for older API or if GetItem fails lists = [] try: lists.append(board.GetTracks()) except: pass try: lists.append(board.GetFootprints()) except: pass try: lists.append(board.GetDrawings()) except: pass try: lists.append(board.Zones()) except: pass for lst in lists: for candidate in lst: if get_item_uuid(candidate) == uuid: item = candidate break if item: break if item: return cast_item(item) return None