Implemented the vector icon editor, library previews, and workspace camera controls.
Key changes: Component Options now has an “Edit Icon…” button instead of direct shape/color fields. Icon editor supports:Rectangles with configurable corner radius Circles and ellipses Lines Triangles Text Movable/selectable shapes Shape context menus Line style and width Solid or transparent fill Stroke and fill colours through Qt’s colour picker Editable shape dimensions Deleting selected shapes Input anchors are green and output anchors red; both can be dragged around the icon. Icons use a 120×80 vector coordinate system and are stored as editable elements in document JSON. Components render their vector icons directly in the workspace. Library and document trees display 16×16 icon previews. Added a Camera toolbar:Zoom In Zoom Out Center Mouse-wheel zoom works directly over the workspace. Icon changes and port positions support undo/redo.
This commit is contained in:
@@ -40,24 +40,49 @@ class Icon:
|
||||
fill: str = "#f4f4f4"
|
||||
border: str = "#303030"
|
||||
text: str = ""
|
||||
width: float = 120.0
|
||||
height: float = 80.0
|
||||
elements: list[dict[str, Any]] = field(default_factory=list)
|
||||
|
||||
def to_dict(self) -> dict[str, str]:
|
||||
def __post_init__(self) -> None:
|
||||
if not self.elements:
|
||||
self.elements = [{
|
||||
"type": "ellipse" if self.shape == "ellipse" else "rectangle",
|
||||
"x": 1.0, "y": 1.0, "width": self.width - 2.0, "height": self.height - 2.0,
|
||||
"fill": self.fill, "stroke": self.border, "lineWidth": 1.5,
|
||||
"lineStyle": "solid", "cornerRadius": 5.0,
|
||||
}]
|
||||
if self.text:
|
||||
self.elements.append({
|
||||
"type": "text", "x": 8.0, "y": 8.0,
|
||||
"width": self.width - 16.0, "height": self.height - 16.0,
|
||||
"text": self.text, "color": "#202020", "fontSize": 12.0,
|
||||
})
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"shape": self.shape,
|
||||
"fill": self.fill,
|
||||
"border": self.border,
|
||||
"text": self.text,
|
||||
"size": {"width": self.width, "height": self.height},
|
||||
"elements": deepcopy(self.elements),
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict[str, Any] | None) -> "Icon":
|
||||
data = data or {}
|
||||
return cls(
|
||||
size = data.get("size", {})
|
||||
icon = cls(
|
||||
shape=str(data.get("shape", "rectangle")),
|
||||
fill=str(data.get("fill", "#f4f4f4")),
|
||||
border=str(data.get("border", "#303030")),
|
||||
text=str(data.get("text", "")),
|
||||
width=float(size.get("width", 120.0)),
|
||||
height=float(size.get("height", 80.0)),
|
||||
elements=deepcopy(data.get("elements", [])),
|
||||
)
|
||||
return icon
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -318,7 +343,7 @@ def clone_component(source: Component) -> Component:
|
||||
y=current.y,
|
||||
inputs=[Port(port.id, port.name, port.x, port.y, deepcopy(port.properties)) for port in current.inputs],
|
||||
outputs=[Port(port.id, port.name, port.x, port.y, deepcopy(port.properties)) for port in current.outputs],
|
||||
icon=Icon(**current.icon.to_dict()),
|
||||
icon=Icon.from_dict(current.icon.to_dict()),
|
||||
properties=deepcopy(current.properties),
|
||||
implementation_kind=current.implementation_kind,
|
||||
graph=graph if current.implementation_kind == "graph" else Graph(),
|
||||
|
||||
Reference in New Issue
Block a user