From 60a30d4ee33beef7eb76c0f2af8534afebbcd67f Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Mon, 17 Aug 2026 18:26:41 +0200 Subject: [PATCH] Start with signal lib --- icons/signal_base.json | 25 + icons/signal_source_base.json | 55 + lib/bondgraph.beb | Bin 1893 -> 1977 bytes lib/signal.beb | Bin 0 -> 677 bytes lib/signal_sources.beb | Bin 0 -> 1352 bytes .../controllers/library_controller.py | 1 + src/bedit_gui/ui/forms/main_window.ui | 12 + src/bedit_gui/ui/forms/main_window_ui.py | 8 + src/bedit_gui/utils/icon.py | 10 + src/bedit_gui/views/graph_editor_widget.py | 48 +- src/bedit_gui/views/icon_graphics_scene.py | 4 +- untitled.bedit.json | 937 +++++++++++++++--- 12 files changed, 928 insertions(+), 172 deletions(-) create mode 100644 icons/signal_base.json create mode 100644 icons/signal_source_base.json create mode 100644 lib/signal.beb create mode 100644 lib/signal_sources.beb diff --git a/icons/signal_base.json b/icons/signal_base.json new file mode 100644 index 0000000..83d204a --- /dev/null +++ b/icons/signal_base.json @@ -0,0 +1,25 @@ +{ + "shapes": { + "14409738-45af-40c5-9c9e-827218d54a95": { + "layer": 0, + "type": "rectangle", + "pos": [ + -48, + -48 + ], + "width": 96.0, + "height": 96.0, + "line_type": "solid", + "line_thickness": 5.0, + "corner_radius": 8.0, + "line_color": "#00007fff", + "fill_color": "#ebebebff" + } + }, + "port_positions": { + "d5681d1d-70ee-4623-a41a-5a572e46d42c": [ + -8, + -8 + ] + } +} diff --git a/icons/signal_source_base.json b/icons/signal_source_base.json new file mode 100644 index 0000000..b802634 --- /dev/null +++ b/icons/signal_source_base.json @@ -0,0 +1,55 @@ +{ + "shapes": { + "9ed4189a-123b-431f-a6bc-bbf169487703": { + "layer": 0, + "type": "rectangle", + "pos": [ + -48, + -48 + ], + "width": 96.0, + "height": 96.0, + "line_type": "solid", + "line_thickness": 5.0, + "corner_radius": 8.0, + "line_color": "#00007fff", + "fill_color": "#ebebebff" + }, + "ac1b7cf2-ce50-44b7-9f8f-077ca36f7369": { + "layer": 4, + "type": "line", + "pos": [ + -32, + -32 + ], + "end": [ + -32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "2e623060-349e-4a48-97b0-a81921df5870": { + "layer": 2, + "type": "line", + "pos": [ + -32, + 32 + ], + "end": [ + 32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + } + }, + "port_positions": { + "37eb6e52-6e89-4e09-8923-43c6230f5486": [ + -8, + -8 + ] + } +} diff --git a/lib/bondgraph.beb b/lib/bondgraph.beb index ae4b762f3406eae16cbee70b19ea54d5cba02865..ef8b4c6c84f640cf2fedb1f090eb817031543646 100644 GIT binary patch literal 1977 zcmV;q2S)fpMM3}o0004aoXuG~ZyeVZmb#?NPuReVKsIol`+kIQV#Jk;1cuZE5QN2j zoGVVS+}+H~>X9l|95@aTz#`yYa!7_0WlHiRwO|2hhyX^q?f3^$1PBlpDRO3ZNv=rB zTFC~bDad);=Q-c`zVDKM*vZ3k#n-(nP*%loaQ5ROO}ZjzV`(%*S{sNo42U;Y65)6X zMhi|IT^sln*!uZ!kS>>gw7gahhxPlDu7n8GW=1$Lj$KtC-kD4?W0V4u5FCB4?R)#J ztzu9^nSF$J*GI#$u5L`andPK$4idcqB0+ExoMA*rX$6D?#_Kzf_1%?mzb;1oA{O=aFSl`*WpS-n6~BemvuC#xRIw~ZP4inDX}IEx z0WRVyl%GdGu6!T+^hPCQC}9xc^XY8~sRubXvk%Ahr0b(ek&8qUlNcx_G;x7@!Wk&7 zWc1wI4-QwmQ5Ba5zTd8Qy{df;hil%z0iS8ncdq#U7^YDu!S^?RGxmcTd)-@L@aQ z!}--c+$mN@eOQ43?h>Eh`|R=OcF;}05t^sF31S~t+uT>5|roKFR$XK(d&6>XY_j0s(tt4xHRc%tGGc(5kW&FQVK?#XPB=H+=i%> z&wL8UkAKZh#3Q9qF$A!oQ6QduCKik!Mr+_EG0vHI9y~t!c6i*WioxYR^m2cAwO0&q zquFyQ5rmW(+-P==1mglx8I;qEQ%czrka#;kKMEf{5rs2Q%%Sji&yR_llg`07o%1+N zr@Gi3^?upCgxSWM3*DvTsQK^^Dj$8C8(3UqmpZR?M)(V{GC5a`SI$)zi|M=K5<&+n zyHj+EL5KaM9sbo8a$g+0=F``m{%|;&{HTN1eE;bj1)0s#+~7Q$Fi6e7h(@X@P01VL z6vZU5Ac&WkuI!}bDRU&hFeAtF$H0h1Ok>PhGlXCW9+RxFh&iW(fj3k{i}+X7Ioh1BzU%0}5_JbXc7O z3EV`BCCa?BFF-Ty&opC}+(tDLm&{U)h6Qq?ZfFhAVkr`2G$OLVxPd3B#<%b;r=%L+ zT+<(IH<@q60G1{{Y{X#3;?JT2e``cwrXFwXlRnIoerA$MhZu-XqN9d@W;&`wqQWxI z)>BW-jP&0=2~FUtI!Ei`e6B?fKMai@ z&If+DKrlwZ0`(b40!9&x6dj0nm>{PF9<8`_u+ME5@=3yF6>2v_F$ZRm9Cb3pT9=5% z14eKb;pzQLC|pW2=L9zdvO&G2C|r(8q`WA(z>6urFI@Sh5H5JSa5b52?By)io48pl zyV~FQq=-00a~pgGH;x|h*PGAPf@k#`8`ZKOLF-w(HQalNMCKEb91IDJp$GChXJ*i| zWcjD{zP}FTnYA`*HC(IzG8$H^dwc6wi&QV~zWL6X_S#s6;_`BR@Vp*}{b9NF3T>~P z5jXwxXrrhx&+*H(CgcZg+hK3NwbOzOM=#olEcmyB)vv!^?AX5ggT2L$k8=?MpJ`w! z6O|HT%hATwX-bm8Li5_-`OKeQgxCoYTHrL>Mre`acBi1xRQE^5^CJDuOB<$ja%OYenQ>w+#B4>rU z2pK0`&XHlLGjD`Rq5H%cQUsF)B&BG0LWI8h>L5hF`i??`$Co29TJZ4F#%K{IJ-2lm zF(8TK_tcy&JgReOz?z~@XnR<)6iyEu^f)*cG4}1o7xC4r-``uz9L_~31g3pzaDgF0 za0paxjijW!qd|iSNOY$cp|_7mXc4p8MraYI*p|;Cj%6-FnR#IW7_nZ7<}VJ3U_n~K zcw~|a9=vgHWX|_tqEx L`t$z*)`M;>)w0UJ literal 1893 zcmV-r2b%aoMM3}o0004aoXuECZyd)Jmi|G0!UP!vvVn4HUqU!B;*$>!4C!J(5C*lp z5<8eJ-91`ziWLWr0~oLfi5y?O! z+o0HoVRdzF?|tum?<@X(H;>AJuY1>^tcua_{3k`4c16&}(rAdZHV|nT5O1s`!toT0 z7Mwb|KJ)|F{>5mRu9kkhx?YY(^#{|ggb37TMmR8zQ&k||nM^Wclme3w9DTo?d-u)l zVpv0&eT4Tm#-p;XZcV$H<)m>B61@Q;L2weBVMIu21%w2~>pyHaqkHwuF{}qXz-+nk zb}CAUHCnMz49AoD{$SFti*dh*MSb(D9kjA6ZuF|+H?Vg8{7!-@mc_UkerGd{2EG{L zA+AIDMf8)(_i;{dTtbEth7rD)HA_f6$hp~lG^wXuA5Dr}B$Aj!M=_y^3)~aVKxrkT z=iYvJc-qaXxH|Ox_PiTa?Q1wZ^Cm9%LWjP0&G#oT^Fj%}zxC^hAJ#bQ&iZ6n)OYTU zeTn;^hpYFdU9KYyK3gIk;7K7n;B(F&Ot@07JAA-{1fI+4pwQEx;9;xBCfVA5Yt~tB)TQxLV=+z5UPC?R%}WIkmYA9}ezy51{> z3t0d5+k1X(+BsOKa}fdWRF}Ks-Y>gX(5KkA)Lr>Y+nraAWAyPMFn{_iHy~VQS30kD z#`p)3nO>+SgA3K=V%Aq&L7*^?Iz^`#cGyqbZC+^s{_>!k&$>JP(P%vVaR;Bp`LjI= zGT)_X;67V0OwGcGJ=K(^vh1{zon;EPF9zHwjB#-kPFV9?# zFT~I7`?EAIUu|-F+GWWggaSxTSrQq7BLRyHaV{G#v=KbPJc%#C$w+E$Dd$8p>yZ33 zvOr=A10&^x-yBf>TqIwZpq~%r!(7~WrlLHHXJ%XmnlJ#R#Q+poVyt75xXc8jkx@u= zjwifaJZ~?>3u{|5Tw!G^&j}liL=dd}j`oo5L=bZT> zocq^?a_3zA`aZ?NBE@DVnRMv!=p?E|2q+YzN+c>ws%$;=)XXXNt&`LqIIkl@Miir% z*+wd4ED=c*CWA88NTFT=#eR0E_Syp5YCY~$NSb01NFEv)C5X-V<4lx6ptRy%oeiz$ zV+O+^VM;Y8MY&EaHc1KsKx#}0s^`2>oVhx%q}GE*>*WKjS70zk!2c<`a<|3<(Ucz1i!WnL&k+?)?2UDaHIb7 zcvP)DeY$bINcHO88}FQJpUqV$uCCSx?;CN{AC=obqV1D2#!Wvx*(_?rIexX?xcp#j zyX@UJciSMt)r;06OWupuzWHXkE9u$~o-TJaTJR9~OaoJysFX0a9Bnj|rX(3mG_Q@6 z!JnRo*bxscc~fgWw9LI=!EmMmRXS;6l)~W-rHWTh5^$(Q!3XpfKRv@Q9uJLW?kTO| zIx5bn$ONKmh{7VjiG)+Ua9M;b4X8FWmJ!?w9x_h4oFgMDXWrBsg%S>TND)jHkd&g~ z|9I%@uMb@G?)T&(yaOB$j%98Dt&f(GqYI|nhz>~{zo$l`dn~%4iNO?oLN&vZrEq$| zL5~~0j5?kfzJ!!pFgygNeQMxF%Mo*dbyg#VDDP;{U;@(8=^6gk@vK-zTDFESqwCtN zSVmtgcqlV3EC3_cE79D>6Tv*Qgz?BE6+C$3PBSa=@!(iS@Su-AuL@K%v*NyAd4G4b z@;>q?f389Aa4ZsoF*bT_Ny8dQI1J+smn2+hFEO{k7`Agbq2-b#rhK>^M}zTbh>8Q% z4+Ra`8IrZd36fG0A{Hl5UMLPWM$TLD^JzI5cEbMus~eTs=(u74d*|lQR+`L&%HA8@ zS1?`yBt7;fmPaX^>g8*f3lxH1(KmYITrqK$gy`R4m-u}nGw*R|{a%FXtHj=NZ f{)6_nSC9HodQ@|JKYRGM|J?cVpCA1XWoO-kx<8s7 diff --git a/lib/signal.beb b/lib/signal.beb new file mode 100644 index 0000000000000000000000000000000000000000..2f85aa639f71716ef2062b4100cd887d12f8d326 GIT binary patch literal 677 zcmV;W0$Tk-MM3}o0004aoUK#KZWA#SZT^7|h(uRNM)UAIEQHi0603?0yU1f-Csv%9 zVeEm1U8*7ktI|Ixor#jPjfD7tsM~J3?E=1|OFWadsF9Gmz~1=U_a2{fAD@;YD@N4x z-b0~fmUg~Ne!We2=p+dNltf{Sa1?|nb|MGG#M-{=L=o^Rr6V|hBl{^;-9%+whNTl zV1_Uk0m3e~5D@?p7<`wo!1YAuYyr-&!7PBgVs@c1erp89Csxp;kWpe{0VI&qP zaEXI3G`Vs82+=SO38vijlYcTR|1zs(`d^7Ha$49gY$CO-fEU{o#j%fKOgx)D*ODYo zh+OVq!G$2M2cOrRhINa4;yrgZ|JdNO`Q-zCOF7CFj370%u@8Pev|G>_ScJwp#cgaxR%gY>o-lu)o>Db@Qwr*@yd6 zJ)k)>J%_9P3&>-T3ky|yLR!wDK z&#Z;~zWQ}1WOqZz?y9xx4H8w7DSk1PhT2}fsG5$s+B zcy}{1>%_T1NKkSjeglGSVFQ+;aYktwTO3OsNQ<(K___FA_!!M%14WN!1;)_$%UOda{N zH=cHrX?Jg9T6fi?u2R)){e71lZmRFs+Uf_~K700V#x^z8q@VxbU=!*o&TZ~A2=$$B zr!ea1s|P#NQPn*-m;gaW!rNY(4LKwy4KFNYA(@USScKphIaxRc;f=O87NGL(-12Sl zIbU641<&e|&*7U5C8naRGmL}fOuHBus34gP+6P}8M`q90NsiuwU@7tSyRAjA!dhO_SdvpKU?Qef=4ZavGkPa>kx@rSI z%NJ)u$U^HPGn2-8;!u$+3MZIKGRlxuEH*7Tw42CGcN~dy2;P9vECGEhI+0Kjd|0u0lM;-(#1<|By+8nDG0jvU+@4jxGz$|Nz6 zdj*ha8YynxdStya064F?H?KE%v!RnAO3aQGVH{~A(wZfb7I0UDEYT-iD!{GFuWL>2 zMdlevb+n*0A$aB?dgc@e5gZDP`WV%@^>*@fcA+O~RpxRt`0|Uv0@-l1Sah7PXYuSjav`r8OCUR$l5yZ!6-g!S**Ub_wxY_HFTp~S$Q1?F^5cb5eN zA`ZjgQgJy`gyGlS8n&=Gv(x*$-*X#AS8BXH8MoX2(6RenmAmzam%ctTKlawKy0YFq z8}HZEXc2_nc3fBaa4}x5(l;Y)+lQAvUd+3n#?1(uwFYuErN@KCM{ zS4uf3Rb3xF#Mqyu%!VbG08l&=ycbdE=2&Dk@5Dw?cNcO5Z`U?736mZj#aI-J!4bR9qzGVQ`A7anOl@_Lh;TXJs_R zq|_>$LI2BM7HV-;jVROwKH6OOk{d8Hh~v+ZZK?0os-H zBKkf#9r~W6nVZx1B)!KGeSaqUYVs(PSVJ-bR(f1?3sD2ABMKoNUw)#RQeG{JK)(6^9$d&~yJ;jZ9OWkacs+=-?O)q9H#y*Kj zk~kGpkik;Jd57b=zD$+;oSLGqAz7o21`GI^k0@!B)Za81W9*B`9$)FT5`XH z@WBd%b4v)1Ul9VQ9XH<6-zicyXd9^m;dB8WF(gfe8jb?-;VOj3i$J^@g#Rb;Nt${} K;(q}N;6wS#M3bHX literal 0 HcmV?d00001 diff --git a/src/bedit_gui/controllers/library_controller.py b/src/bedit_gui/controllers/library_controller.py index 8243578..026664d 100644 --- a/src/bedit_gui/controllers/library_controller.py +++ b/src/bedit_gui/controllers/library_controller.py @@ -35,6 +35,7 @@ class LibraryController(QObject): tree.header().setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed) tree.setColumnWidth(1, 56) + window.ui.actionReload_Libraries.triggered.connect(self.reload) self.reload() def reload(self) -> None: diff --git a/src/bedit_gui/ui/forms/main_window.ui b/src/bedit_gui/ui/forms/main_window.ui index fedf032..e3b4011 100644 --- a/src/bedit_gui/ui/forms/main_window.ui +++ b/src/bedit_gui/ui/forms/main_window.ui @@ -59,6 +59,7 @@ + @@ -351,6 +352,17 @@ Settings + + + Reload Libraries + + + Reload configured libraries + + + QAction::MenuRole::NoRole + + diff --git a/src/bedit_gui/ui/forms/main_window_ui.py b/src/bedit_gui/ui/forms/main_window_ui.py index 0df19d5..414054c 100644 --- a/src/bedit_gui/ui/forms/main_window_ui.py +++ b/src/bedit_gui/ui/forms/main_window_ui.py @@ -83,6 +83,9 @@ class Ui_MainWindow(object): self.actionToolbars.setObjectName(u"actionToolbars") self.actionSettings = QAction(MainWindow) self.actionSettings.setObjectName(u"actionSettings") + self.actionReload_Libraries = QAction(MainWindow) + self.actionReload_Libraries.setObjectName(u"actionReload_Libraries") + self.actionReload_Libraries.setMenuRole(QAction.MenuRole.NoRole) self.actionDelete = QAction(MainWindow) self.actionDelete.setObjectName(u"actionDelete") icon7 = QIcon() @@ -228,6 +231,7 @@ class Ui_MainWindow(object): self.menuEdit.addAction(self.actionDelete) self.menuEdit.addSeparator() self.menuEdit.addAction(self.actionSettings) + self.menuEdit.addAction(self.actionReload_Libraries) self.menuView.addAction(self.actionReset_Layout) self.menuView.addAction(self.actionPanels) self.menuView.addAction(self.actionToolbars) @@ -310,6 +314,10 @@ class Ui_MainWindow(object): self.actionPanels.setText(QCoreApplication.translate("MainWindow", u"Panels", None)) self.actionToolbars.setText(QCoreApplication.translate("MainWindow", u"Toolbars", None)) self.actionSettings.setText(QCoreApplication.translate("MainWindow", u"Settings", None)) + self.actionReload_Libraries.setText(QCoreApplication.translate("MainWindow", u"Reload Libraries", None)) +#if QT_CONFIG(tooltip) + self.actionReload_Libraries.setToolTip(QCoreApplication.translate("MainWindow", u"Reload configured libraries", None)) +#endif // QT_CONFIG(tooltip) self.actionDelete.setText(QCoreApplication.translate("MainWindow", u"Delete", None)) #if QT_CONFIG(tooltip) self.actionDelete.setToolTip(QCoreApplication.translate("MainWindow", u"Delete selected", None)) diff --git a/src/bedit_gui/utils/icon.py b/src/bedit_gui/utils/icon.py index 9d7c780..267f806 100644 --- a/src/bedit_gui/utils/icon.py +++ b/src/bedit_gui/utils/icon.py @@ -1,5 +1,7 @@ from __future__ import annotations +from math import ceil + from PySide6.QtCore import QRectF, QSize, Qt from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPainter, QPen, QPixmap, QRegion @@ -8,6 +10,7 @@ from bedit_gui.models import Icon, Line, LineType, Rectangle, Text PORT_SIZE = 16 DEFAULT_ICON_SIZE = QSize(48, 48) +EMPTY_NATURAL_ICON_SIZE = QSize(32, 32) ICON_MARGIN = 4 ICON_PREVIEW_OVERSAMPLE = 4 @@ -43,6 +46,13 @@ def get_pixmap_bounding_box(pixmap: QPixmap) -> QRectF: return QRectF(bounds) if not bounds.isEmpty() else QRectF(0, 0, pixmap.width(), pixmap.height()) +def get_natural_icon_size(icon: Icon) -> QSize: + bounds = get_bounding_box(icon) + if bounds.isEmpty(): + return QSize(EMPTY_NATURAL_ICON_SIZE) + return QSize(max(1, ceil(bounds.width()) + ICON_MARGIN), max(1, ceil(bounds.height()) + ICON_MARGIN)) + + def render_icon(icon: Icon, ports: dict[PortID, Port], size: QSize = DEFAULT_ICON_SIZE, render_ports: bool = False) -> QIcon: pixmap = QPixmap(size) pixmap.fill(Qt.GlobalColor.transparent) diff --git a/src/bedit_gui/views/graph_editor_widget.py b/src/bedit_gui/views/graph_editor_widget.py index 3185375..e7a027d 100644 --- a/src/bedit_gui/views/graph_editor_widget.py +++ b/src/bedit_gui/views/graph_editor_widget.py @@ -5,7 +5,7 @@ from enum import Enum from itertools import pairwise from math import hypot -from PySide6.QtCore import QEvent, QObject, QPointF, QRectF, QSize, QTimer, Qt, Signal +from PySide6.QtCore import QEvent, QObject, QPointF, QRectF, QTimer, Qt, Signal from PySide6.QtGui import QActionGroup, QBrush, QColor, QCursor, QDragEnterEvent, QDragMoveEvent, QDropEvent, QKeySequence, QMouseEvent, QPainter, QPainterPath, QPen, QShortcut, QWheelEvent from PySide6.QtWidgets import QGraphicsEllipseItem, QGraphicsItem, QGraphicsPathItem, QGraphicsPixmapItem, QGraphicsScene, QGraphicsSceneMouseEvent, QGraphicsTextItem, QGraphicsView, QMenu, QWidget @@ -13,7 +13,7 @@ from bedit_core.models import BondCausality, BondConnection, BondPort, Component from bedit_gui.models import Graph, GraphComponentLabel, GraphConnection, Icon from bedit_gui.services.component_clipboard import COMPONENTS_MIME from bedit_gui.ui.generated.ui_graph_editor_widget import Ui_graphEditorWidget -from bedit_gui.utils.icon import get_pixmap_bounding_box, render_icon +from bedit_gui.utils.icon import get_natural_icon_size, get_pixmap_bounding_box, render_icon GRID_SPACING = 64 SCENE_SIZE = 10000 @@ -21,14 +21,18 @@ MIN_ZOOM = 0.2 MAX_ZOOM = 4.0 ZOOM_STEP = 1.15 ZOOM_TO_FIT_PADDING = 32.0 -COMPONENT_ICON_SIZE = QSize(128, 128) COMPONENT_LABEL_FONT_SIZE = 24.0 FALLBACK_COMPONENT_SPACING = 128 CONNECTION_WIDTH = 4.0 -CONNECTION_BOUNDING_BOX_SPACING = 16.0 +BOND_CONNECTION_COLOR = "#000000" +SIGNAL_CONNECTION_COLOR = "#00007f" +BOND_CONNECTION_BOUNDING_BOX_SPACING = 16.0 +SIGNAL_CONNECTION_BOUNDING_BOX_SPACING = 0.0 CONNECTION_STRAIGHTEN_TOLERANCE = 8.0 ARROW_LENGTH = 32.0 ARROW_HALF_WIDTH = 16.0 +SIGNAL_ARROW_LENGTH = ARROW_LENGTH / 2 +SIGNAL_ARROW_HALF_WIDTH = ARROW_HALF_WIDTH / 2 CAUSALITY_TICK_HALF_LENGTH = 16.0 @@ -66,8 +70,10 @@ class GraphConnectionItem(QGraphicsPathItem): self.connection_id = connection_id self.editor = editor self.setPath(self._connection_path(points, half_arrow, tick_at_source)) - pen = QPen(QColor("#202020"), CONNECTION_WIDTH) + color = QColor(BOND_CONNECTION_COLOR if half_arrow else SIGNAL_CONNECTION_COLOR) + pen = QPen(color, CONNECTION_WIDTH) self.setPen(pen) + self.setBrush(QBrush(color)) self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable) self.setZValue(-1) @@ -100,15 +106,17 @@ class GraphConnectionItem(QGraphicsPathItem): dx = target.x() - previous.x() dy = target.y() - previous.y() length = hypot(dx, dy) - back_x = target.x() - ARROW_LENGTH * dx / length - back_y = target.y() - ARROW_LENGTH * dy / length - perpendicular_x = -ARROW_HALF_WIDTH * dy / length - perpendicular_y = ARROW_HALF_WIDTH * dx / length + arrow_length = ARROW_LENGTH if half_arrow else SIGNAL_ARROW_LENGTH + arrow_half_width = ARROW_HALF_WIDTH if half_arrow else SIGNAL_ARROW_HALF_WIDTH + back_x = target.x() - arrow_length * dx / length + back_y = target.y() - arrow_length * dy / length + perpendicular_x = -arrow_half_width * dy / length + perpendicular_y = arrow_half_width * dx / length path.moveTo(target) path.lineTo(back_x + perpendicular_x, back_y + perpendicular_y) if not half_arrow: - path.moveTo(target) path.lineTo(back_x - perpendicular_x, back_y - perpendicular_y) + path.closeSubpath() if tick_at_source is not None: GraphConnectionItem._add_causality_tick(path, points, tick_at_source) return path @@ -315,6 +323,7 @@ class GraphEditorWidget(QWidget): self.scene = GraphGraphicsScene(self) self.scene.setSceneRect(-SCENE_SIZE / 2, -SCENE_SIZE / 2, SCENE_SIZE, SCENE_SIZE) self.ui.graphicsView.setScene(self.scene) + self.ui.graphicsView.setRenderHint(QPainter.RenderHint.Antialiasing) self.ui.graphicsView.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse) self.ui.graphicsView.viewport().installEventFilter(self) self.ui.graphicsView.viewport().setAcceptDrops(True) @@ -381,7 +390,8 @@ class GraphEditorWidget(QWidget): positions = {component_id: graph.component_positions.get(component_id, (index * FALLBACK_COMPONENT_SPACING, 0)) for index, component_id in enumerate(component.implementation.graph.components)} for component_id, child in component.implementation.graph.components.items(): icon = icons.get(component_id, Icon()) - pixmap = render_icon(icon, child.interface.ports, COMPONENT_ICON_SIZE, render_ports=self._mode is GraphEditorMode.CONNECTION).pixmap(COMPONENT_ICON_SIZE) + icon_size = get_natural_icon_size(icon) + pixmap = render_icon(icon, child.interface.ports, icon_size, render_ports=self._mode is GraphEditorMode.CONNECTION).pixmap(icon_size) item = GraphComponentItem(component_id, pixmap, self) item.setOffset(-pixmap.width() / 2, -pixmap.height() / 2) item.setPos(*positions[component_id]) @@ -435,7 +445,8 @@ class GraphEditorWidget(QWidget): points = self._straighten_direct_connection(points) source_bounds = self._component_bounds[source_component].translated(*source_position) target_bounds = self._component_bounds[target_component].translated(*target_position) - points = self._clip_connection(points, source_bounds, target_bounds) + spacing = BOND_CONNECTION_BOUNDING_BOX_SPACING if isinstance(connection, BondConnection) else SIGNAL_CONNECTION_BOUNDING_BOX_SPACING + points = self._clip_connection(points, source_bounds, target_bounds, spacing) tick_at_source = None if isinstance(connection, BondConnection): tick_at_source = False if connection.causality is BondCausality.EFFORT_OUT else True if connection.causality is BondCausality.FLOW_OUT else None @@ -582,7 +593,7 @@ class GraphEditorWidget(QWidget): return points @staticmethod - def _clip_connection(points: list[tuple[float, float]], source_bounds: QRectF, target_bounds: QRectF) -> list[tuple[float, float]]: + def _clip_connection(points: list[tuple[float, float]], source_bounds: QRectF, target_bounds: QRectF, spacing: float) -> list[tuple[float, float]]: source = points[0] target = points[-1] source_direction = next((point for point in points[1:] if point != source), None) @@ -590,13 +601,13 @@ class GraphEditorWidget(QWidget): if source_direction is None or target_direction is None: return points clipped = list(points) - clipped[0] = GraphEditorWidget._bounding_box_edge(source_bounds, source, source_direction) - clipped[-1] = GraphEditorWidget._bounding_box_edge(target_bounds, target, target_direction) + clipped[0] = GraphEditorWidget._bounding_box_edge(source_bounds, source, source_direction, spacing) + clipped[-1] = GraphEditorWidget._bounding_box_edge(target_bounds, target, target_direction, spacing) return clipped @staticmethod - def _bounding_box_edge(bounds: QRectF, origin: tuple[float, float], toward: tuple[float, float]) -> tuple[float, float]: - bounds = bounds.adjusted(-CONNECTION_BOUNDING_BOX_SPACING, -CONNECTION_BOUNDING_BOX_SPACING, CONNECTION_BOUNDING_BOX_SPACING, CONNECTION_BOUNDING_BOX_SPACING) + def _bounding_box_edge(bounds: QRectF, origin: tuple[float, float], toward: tuple[float, float], spacing: float) -> tuple[float, float]: + bounds = bounds.adjusted(-spacing, -spacing, spacing, spacing) dx = toward[0] - origin[0] dy = toward[1] - origin[1] horizontal_scale = (bounds.right() - origin[0]) / dx if dx > 0 else (bounds.left() - origin[0]) / dx if dx < 0 else float("inf") @@ -664,7 +675,8 @@ class GraphEditorWidget(QWidget): self._connection_preview.setPath(QPainterPath(mouse_position)) return bounds = self._component_bounds[self._connection_start].translated(*source) - start = self._bounding_box_edge(bounds, source, (mouse_position.x(), mouse_position.y())) + spacing = max(BOND_CONNECTION_BOUNDING_BOX_SPACING, SIGNAL_CONNECTION_BOUNDING_BOX_SPACING) + start = self._bounding_box_edge(bounds, source, (mouse_position.x(), mouse_position.y()), spacing) path = QPainterPath(QPointF(*start)) path.lineTo(mouse_position) self._connection_preview.setPath(path) diff --git a/src/bedit_gui/views/icon_graphics_scene.py b/src/bedit_gui/views/icon_graphics_scene.py index 2b73146..f0e1fca 100644 --- a/src/bedit_gui/views/icon_graphics_scene.py +++ b/src/bedit_gui/views/icon_graphics_scene.py @@ -11,6 +11,8 @@ from PySide6.QtWidgets import QGraphicsItem, QGraphicsLineItem, QGraphicsPathIte from bedit_core.models import Port, PortID, SignalDirection from bedit_gui.models import Icon, Line, LineType, Rectangle, Shape, ShapeID, Text +ICON_SCENE_SIZE = 512 + class ShapeCreationTool(Protocol): def begin(self, position: QPointF) -> None: ... @@ -356,7 +358,7 @@ class IconGraphicsScene(QGraphicsScene): super().__init__(parent) self._tool: ShapeCreationTool | None = None self._ports: dict[PortID, Port] = {} - self.setSceneRect(-64, -64, 128, 128) + self.setSceneRect(-ICON_SCENE_SIZE / 2, -ICON_SCENE_SIZE / 2, ICON_SCENE_SIZE, ICON_SCENE_SIZE) def set_ports(self, ports: dict[PortID, Port]) -> None: self._ports = deepcopy(ports) diff --git a/untitled.bedit.json b/untitled.bedit.json index 6595062..cea3e7f 100644 --- a/untitled.bedit.json +++ b/untitled.bedit.json @@ -73,42 +73,6 @@ ] } }, - "9ee2f42b-5ed1-446d-8790-c2a1df6b61d3": { - "name": "j1", - "interface": { - "ports": { - "4306701a-6b1b-4d19-b8ff-45dbfa04f2d3": { - "port_type": "bond", - "name": "p", - "direction": "input", - "multiplicity": true, - "matrix_size": [ - 1, - 1 - ], - "description": "", - "domain": "power", - "causality_preference": "single_flow_in" - } - } - }, - "parameters": {}, - "implementation": { - "implementation_type": "equation", - "declarations": [ - "parameter Real s[$p_N$] = $p_S$;", - "Real f;" - ], - "initial_equations": [], - "equations": [ - "f = s[1] * p[1].f;", - "sum(s[i] * p[i].e for i in 1:$p_N$) = 0;", - "for i in 2:$p_N$ loop", - " s[i] * p[i].f = s[i-1] * p[i-1].f;", - "end for;" - ] - } - }, "5a8b2e8d-489f-467b-8282-7e344dfad576": { "name": "R", "interface": { @@ -182,6 +146,20 @@ "description": "", "domain": "power", "causality_preference": "fixed_effort_out" + }, + "239bd18c-ff3d-4713-a5a4-0207973afb36": { + "port_type": "signal", + "name": "u", + "direction": "input", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null } } }, @@ -206,46 +184,11 @@ ], "initial_equations": [], "equations": [ - "p.e = e;", + "p.e = u*e;", "f = p.f;" ] } }, - "9f392c28-6bef-4b10-9305-93e250747007": { - "name": "j0", - "interface": { - "ports": { - "497b1f74-1186-471f-976a-36b07a451caf": { - "port_type": "bond", - "name": "p", - "direction": "input", - "multiplicity": true, - "matrix_size": [ - 1, - 1 - ], - "description": "", - "domain": "power", - "causality_preference": "single_effort_in" - } - } - }, - "parameters": {}, - "implementation": { - "implementation_type": "equation", - "declarations": [ - "Real e;" - ], - "initial_equations": [], - "equations": [ - "e = p[1].e;", - "sum(p[i].f for i in 1:$p_N$) = 0;", - "for i in 2:$p_N$ loop", - " p[i].e = p[i-1].e;", - "end for;" - ] - } - }, "77701f68-b14c-4b98-8929-c5fba0261962": { "name": "R0", "interface": { @@ -346,50 +289,378 @@ "p.f = state/i;" ] } + }, + "7e0f1689-4173-42c2-b0c3-4c01cd699fcc": { + "name": "step", + "interface": { + "ports": { + "37eb6e52-6e89-4e09-8923-43c6230f5486": { + "port_type": "signal", + "name": "y", + "direction": "output", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + } + } + }, + "parameters": { + "f609057b-7cd8-4a5d-9243-771c64426c29": { + "name": "v", + "value": "1.0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + }, + "86a87f91-fdc4-4662-9e8b-1855a1f4f577": { + "name": "T", + "value": "1.0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + }, + "901df6e3-671d-467b-91bb-a26654fbf6bb": { + "name": "offset", + "value": "0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + } + }, + "implementation": { + "implementation_type": "equation", + "declarations": [], + "initial_equations": [], + "equations": [ + "y = if time >= T then v+offset else offset;" + ] + } + }, + "aa0ff170-82d0-4f5e-9151-3b8478531e97": { + "name": "const", + "interface": { + "ports": { + "b39afdc2-a419-459a-bdf2-5358bf38103d": { + "port_type": "signal", + "name": "y", + "direction": "output", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + } + } + }, + "parameters": { + "dab851b3-cc1b-42af-878c-5229209fd74d": { + "name": "v", + "value": "1.0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + } + }, + "implementation": { + "implementation_type": "equation", + "declarations": [], + "initial_equations": [], + "equations": [ + "y = v;" + ] + } + }, + "2b3844e8-1875-40d0-ae4e-7a14ca217bce": { + "name": "ramp", + "interface": { + "ports": { + "5807dc83-d049-4f0f-9708-d041a752fcd0": { + "port_type": "signal", + "name": "y", + "direction": "output", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + } + } + }, + "parameters": { + "dc093514-3e2f-4424-9e4f-01a6437c4ca5": { + "name": "d", + "value": "1.0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + }, + "3e4487c8-a3b1-4a51-8aac-3cd66ce7a0b0": { + "name": "offset", + "value": "1.0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + } + }, + "implementation": { + "implementation_type": "equation", + "declarations": [], + "initial_equations": [], + "equations": [ + "y = offset + time*d;" + ] + } + }, + "c07a8cfb-323b-432b-8a6f-23b1a60eb593": { + "name": "gain", + "interface": { + "ports": { + "d5681d1d-70ee-4623-a41a-5a572e46d42c": { + "port_type": "signal", + "name": "y", + "direction": "output", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + }, + "8bd1cc42-03b9-4c46-b31b-c1f46933dc9e": { + "port_type": "signal", + "name": "u", + "direction": "input", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + } + } + }, + "parameters": { + "a4a9e500-5297-45b2-ba5d-7854f2855ec5": { + "name": "k", + "value": "2.0", + "value_type": "real", + "matrix_size": [ + 1, + 1 + ], + "quantity": null, + "unit": null, + "description": null + } + }, + "implementation": { + "implementation_type": "equation", + "declarations": [], + "initial_equations": [], + "equations": [ + "y = k*u;" + ] + } + }, + "6596fb5f-0b16-4f9b-804b-5b8b81db4158": { + "name": "j1", + "interface": { + "ports": { + "44bfb5f7-d8bf-4922-bac8-a001c077893e": { + "port_type": "bond", + "name": "p", + "direction": "input", + "multiplicity": true, + "matrix_size": [ + 1, + 1 + ], + "description": "", + "domain": "power", + "causality_preference": "single_flow_in" + }, + "30d830d5-adc9-4b84-960f-a7b51f68adf4": { + "port_type": "signal", + "name": "f", + "direction": "output", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + } + } + }, + "parameters": {}, + "implementation": { + "implementation_type": "equation", + "declarations": [ + "parameter Real s[$p_N$] = $p_S$;" + ], + "initial_equations": [], + "equations": [ + "f = s[1] * p[1].f;", + "sum(s[i] * p[i].e for i in 1:$p_N$) = 0;", + "for i in 2:$p_N$ loop", + " s[i] * p[i].f = s[i-1] * p[i-1].f;", + "end for;" + ] + } + }, + "8e8dca73-2d11-4631-9c24-5e1a4e3b2920": { + "name": "j0", + "interface": { + "ports": { + "707394db-dff5-4591-b716-23f32b56d4a6": { + "port_type": "bond", + "name": "p", + "direction": "input", + "multiplicity": true, + "matrix_size": [ + 1, + 1 + ], + "description": "", + "domain": "power", + "causality_preference": "single_effort_in" + }, + "a2709c23-7485-43b2-bc87-28a0f4c37c0b": { + "port_type": "signal", + "name": "e", + "direction": "output", + "multiplicity": false, + "matrix_size": [ + 1, + 1 + ], + "description": null, + "value_type": "real", + "quantity": null, + "unit": null + } + } + }, + "parameters": {}, + "implementation": { + "implementation_type": "equation", + "declarations": [], + "initial_equations": [], + "equations": [ + "e = p[1].e;", + "sum(p[i].f for i in 1:$p_N$) = 0;", + "for i in 2:$p_N$ loop", + " p[i].e = p[i-1].e;", + "end for;" + ] + } } }, "connections": { - "7e293c73-1e07-4d4c-b750-6f43870c71c4": { + "00c239f4-b281-4313-9577-15a81f272c2b": { + "connection_type": "signal", + "source": "37eb6e52-6e89-4e09-8923-43c6230f5486", + "target": "239bd18c-ff3d-4713-a5a4-0207973afb36" + }, + "a5735621-1486-4e5e-be46-a5ba406dde78": { "connection_type": "bond", "source": "5b6a8a0c-0875-402c-bd74-11d086aac372", - "target": "4306701a-6b1b-4d19-b8ff-45dbfa04f2d3", + "target": "44bfb5f7-d8bf-4922-bac8-a001c077893e", "causality": "effort_out", "undesired": false }, - "66414b62-ca76-4be6-8da4-72551f8ffc0e": { + "5c0d8fee-a366-4544-adb9-1ac3802a56a6": { "connection_type": "bond", - "source": "497b1f74-1186-471f-976a-36b07a451caf", + "source": "44bfb5f7-d8bf-4922-bac8-a001c077893e", + "target": "c87881f1-23b4-4a69-b586-8e3c7bf6e21e", + "causality": "flow_out", + "undesired": false + }, + "6523c7a3-868a-474b-8e7c-5fb4ee4443a4": { + "connection_type": "bond", + "source": "44bfb5f7-d8bf-4922-bac8-a001c077893e", + "target": "0ac7d4ea-77f7-4c0d-8e37-406ef66e4740", + "causality": "flow_out", + "undesired": false + }, + "b9391149-a6b0-4b53-b338-d9e4990557ce": { + "connection_type": "bond", + "source": "44bfb5f7-d8bf-4922-bac8-a001c077893e", + "target": "707394db-dff5-4591-b716-23f32b56d4a6", + "causality": "effort_out", + "undesired": false + }, + "6163366c-d693-4a9f-962d-27920e510131": { + "connection_type": "bond", + "source": "707394db-dff5-4591-b716-23f32b56d4a6", "target": "4a3f69f2-b305-4305-92e3-3998634ff226", "causality": "effort_out", "undesired": false }, - "1f52dc5a-1847-4982-aabc-2538cf99a86f": { + "610f5a4d-6eff-487e-9782-d08d1f257cfa": { "connection_type": "bond", - "source": "497b1f74-1186-471f-976a-36b07a451caf", + "source": "707394db-dff5-4591-b716-23f32b56d4a6", "target": "0b9036b1-e4e4-437e-8c35-f5bb391b6cbd", "causality": "effort_out", "undesired": false }, - "cfff2ad4-a4ec-4f37-aa36-2c37b01422f0": { - "connection_type": "bond", - "source": "4306701a-6b1b-4d19-b8ff-45dbfa04f2d3", - "target": "497b1f74-1186-471f-976a-36b07a451caf", - "causality": "flow_out", - "undesired": false - }, - "743e35a4-e736-407d-bf34-b4afbcde5a0b": { - "connection_type": "bond", - "source": "4306701a-6b1b-4d19-b8ff-45dbfa04f2d3", - "target": "0ac7d4ea-77f7-4c0d-8e37-406ef66e4740", - "causality": "effort_out", - "undesired": false - }, - "68727b23-888b-45b4-a0f4-801ac7b39601": { - "connection_type": "bond", - "source": "4306701a-6b1b-4d19-b8ff-45dbfa04f2d3", - "target": "c87881f1-23b4-4a69-b586-8e3c7bf6e21e", - "causality": "flow_out", - "undesired": false + "909ab167-31cf-4b10-95ed-082878018970": { + "connection_type": "signal", + "source": "a2709c23-7485-43b2-bc87-28a0f4c37c0b", + "target": "8bd1cc42-03b9-4c46-b31b-c1f46933dc9e" } } } @@ -487,78 +758,32 @@ ] } }, - "9ee2f42b-5ed1-446d-8790-c2a1df6b61d3": { - "shapes": { - "2a5bf670-c821-442b-9d46-1b07faa70722": { - "layer": 0, - "type": "text", - "pos": [ - -32, - -32 - ], - "width": 64.0, - "height": 64.0, - "color": "#000000ff", - "bold": true, - "italic": false, - "size": 64.0, - "text": "1" - } - }, - "port_positions": { - "4306701a-6b1b-4d19-b8ff-45dbfa04f2d3": [ - -8, - -8 - ] - } - }, - "9f392c28-6bef-4b10-9305-93e250747007": { - "shapes": { - "2a5bf670-c821-442b-9d46-1b07faa70722": { - "layer": 0, - "type": "text", - "pos": [ - -32, - -32 - ], - "width": 64.0, - "height": 64.0, - "color": "#000000ff", - "bold": true, - "italic": false, - "size": 64.0, - "text": "0" - } - }, - "port_positions": { - "497b1f74-1186-471f-976a-36b07a451caf": [ - -8, - -8 - ] - } - }, "2804f2f1-6123-4a53-aff1-87a3a8202711": { "shapes": { "2a5bf670-c821-442b-9d46-1b07faa70722": { "layer": 0, "type": "text", "pos": [ - -48, + -77, -32 ], - "width": 96.0, + "width": 152.0, "height": 64.0, "color": "#000000ff", "bold": true, "italic": false, "size": 64.0, - "text": "Se" + "text": "MSe" } }, "port_positions": { "5b6a8a0c-0875-402c-bd74-11d086aac372": [ -8, -8 + ], + "239bd18c-ff3d-4713-a5a4-0207973afb36": [ + -65, + -29 ] } }, @@ -586,6 +811,344 @@ -8 ] } + }, + "7e0f1689-4173-42c2-b0c3-4c01cd699fcc": { + "shapes": { + "9ed4189a-123b-431f-a6bc-bbf169487703": { + "layer": 0, + "type": "rectangle", + "pos": [ + -48, + -48 + ], + "width": 96.0, + "height": 96.0, + "line_type": "solid", + "line_thickness": 5.0, + "corner_radius": 8.0, + "line_color": "#00007fff", + "fill_color": "#ebebebff" + }, + "ac1b7cf2-ce50-44b7-9f8f-077ca36f7369": { + "layer": 4, + "type": "line", + "pos": [ + -32, + -32 + ], + "end": [ + -32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "2e623060-349e-4a48-97b0-a81921df5870": { + "layer": 2, + "type": "line", + "pos": [ + -32, + 32 + ], + "end": [ + 32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "e231a6f0-da98-4e5d-ad1a-7c11048a50fb": { + "layer": 3, + "type": "line", + "pos": [ + -32, + 14 + ], + "end": [ + 3, + 14 + ], + "line_type": "solid", + "line_thickness": 2.0, + "line_color": "#ffaa00ff" + }, + "43393c01-9198-4f64-a158-dc44dce92624": { + "layer": 5, + "type": "line", + "pos": [ + 3, + 14 + ], + "end": [ + 3, + -13 + ], + "line_type": "solid", + "line_thickness": 2.0, + "line_color": "#ffaa00ff" + }, + "45e988a2-393d-4a4c-b692-6c0150072f73": { + "layer": 6, + "type": "line", + "pos": [ + 3, + -13 + ], + "end": [ + 32, + -13 + ], + "line_type": "solid", + "line_thickness": 2.0, + "line_color": "#ffaa00ff" + } + }, + "port_positions": { + "37eb6e52-6e89-4e09-8923-43c6230f5486": [ + -8, + -8 + ] + } + }, + "aa0ff170-82d0-4f5e-9151-3b8478531e97": { + "shapes": { + "3563b7fb-f86d-4df4-90c8-fef103e253e9": { + "layer": 0, + "type": "rectangle", + "pos": [ + -48, + -48 + ], + "width": 96.0, + "height": 96.0, + "line_type": "solid", + "line_thickness": 5.0, + "corner_radius": 8.0, + "line_color": "#00007fff", + "fill_color": "#ebebebff" + }, + "545a1285-8eca-4a11-8cf5-c9ac07d7ddd6": { + "layer": 4, + "type": "line", + "pos": [ + -32, + -32 + ], + "end": [ + -32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "2b8a18b0-7ca4-4c35-98c1-05efaacc6079": { + "layer": 2, + "type": "line", + "pos": [ + -32, + 32 + ], + "end": [ + 32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "15b1b956-ec01-44b9-86f7-6274801deffb": { + "layer": 3, + "type": "line", + "pos": [ + -32, + -9 + ], + "end": [ + 32, + -9 + ], + "line_type": "solid", + "line_thickness": 2.0, + "line_color": "#ffaa00ff" + } + }, + "port_positions": { + "b39afdc2-a419-459a-bdf2-5358bf38103d": [ + -8, + -8 + ] + } + }, + "2b3844e8-1875-40d0-ae4e-7a14ca217bce": { + "shapes": { + "5088d827-d554-4d4a-b2f2-818b2488c5b2": { + "layer": 0, + "type": "rectangle", + "pos": [ + -48, + -48 + ], + "width": 96.0, + "height": 96.0, + "line_type": "solid", + "line_thickness": 5.0, + "corner_radius": 8.0, + "line_color": "#00007fff", + "fill_color": "#ebebebff" + }, + "4d18c283-1f6a-404f-a2e3-85866dce36b6": { + "layer": 4, + "type": "line", + "pos": [ + -32, + -32 + ], + "end": [ + -32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "8433da05-3b9f-421e-9f56-170889d7a609": { + "layer": 2, + "type": "line", + "pos": [ + -32, + 32 + ], + "end": [ + 32, + 32 + ], + "line_type": "solid", + "line_thickness": 3.0, + "line_color": "#000000ff" + }, + "47bf4d6c-bb28-4743-8672-cf39c4177242": { + "layer": 3, + "type": "line", + "pos": [ + -32, + 23 + ], + "end": [ + 32, + -9 + ], + "line_type": "solid", + "line_thickness": 2.0, + "line_color": "#ffaa00ff" + } + }, + "port_positions": { + "5807dc83-d049-4f0f-9708-d041a752fcd0": [ + -8, + -8 + ] + } + }, + "c07a8cfb-323b-432b-8a6f-23b1a60eb593": { + "shapes": { + "14409738-45af-40c5-9c9e-827218d54a95": { + "layer": 0, + "type": "rectangle", + "pos": [ + -48, + -48 + ], + "width": 96.0, + "height": 96.0, + "line_type": "solid", + "line_thickness": 5.0, + "corner_radius": 8.0, + "line_color": "#00007fff", + "fill_color": "#ebebebff" + }, + "630596d8-59a2-4bdc-a4be-bda53c0257b4": { + "layer": 1, + "type": "text", + "pos": [ + -34, + -35 + ], + "width": 68.0, + "height": 71.0, + "color": "#00007fff", + "bold": false, + "italic": false, + "size": 48.0, + "text": "K" + } + }, + "port_positions": { + "d5681d1d-70ee-4623-a41a-5a572e46d42c": [ + -8, + -8 + ] + } + }, + "6596fb5f-0b16-4f9b-804b-5b8b81db4158": { + "shapes": { + "0b6fb297-1cf1-4f93-b64c-7e201dc09c19": { + "layer": 0, + "type": "text", + "pos": [ + -32, + -32 + ], + "width": 64.0, + "height": 64.0, + "color": "#000000ff", + "bold": true, + "italic": false, + "size": 64.0, + "text": "1" + } + }, + "port_positions": { + "44bfb5f7-d8bf-4922-bac8-a001c077893e": [ + -8, + -8 + ], + "30d830d5-adc9-4b84-960f-a7b51f68adf4": [ + 8, + -32 + ] + } + }, + "8e8dca73-2d11-4631-9c24-5e1a4e3b2920": { + "shapes": { + "02c7e2f5-7490-4a5f-abc0-15a584403a9f": { + "layer": 0, + "type": "text", + "pos": [ + -32, + -32 + ], + "width": 64.0, + "height": 64.0, + "color": "#000000ff", + "bold": true, + "italic": false, + "size": 64.0, + "text": "0" + } + }, + "port_positions": { + "707394db-dff5-4591-b716-23f32b56d4a6": [ + -8, + -8 + ], + "a2709c23-7485-43b2-bc87-28a0f4c37c0b": [ + 9, + -32 + ] + } } } }, @@ -630,13 +1193,53 @@ "015a0697-69a9-43bf-9410-d2c8b44303f8": [ 64, 384 + ], + "4e3d1c6f-90a9-44bd-a91e-0619ce0cec63": [ + -460, + -100 + ], + "7e0f1689-4173-42c2-b0c3-4c01cd699fcc": [ + -432, + -128 + ], + "aa0ff170-82d0-4f5e-9151-3b8478531e97": [ + -432, + 48 + ], + "2b3844e8-1875-40d0-ae4e-7a14ca217bce": [ + -432, + 236 + ], + "bf08f999-bfe8-493a-9ad2-9c2965e17d6d": [ + -504, + -292 + ], + "c07a8cfb-323b-432b-8a6f-23b1a60eb593": [ + 64, + 308 + ], + "2cb26679-2488-4766-9ba2-b35c197e327f": [ + 64, + -128 + ], + "408a4376-47c4-456b-ba49-4594b7a18892": [ + 64, + 128 + ], + "6596fb5f-0b16-4f9b-804b-5b8b81db4158": [ + 64, + -128 + ], + "8e8dca73-2d11-4631-9c24-5e1a4e3b2920": [ + 64, + 128 ] }, "component_labels": { "43b3aee6-0b38-429b-9c6d-d38fc097297f": { "relative_position": [ - 68, - -68 + 52, + -44 ], "visible": true }, @@ -653,6 +1256,34 @@ 8 ], "visible": false + }, + "408a4376-47c4-456b-ba49-4594b7a18892": { + "relative_position": [ + 0, + 8 + ], + "visible": false + }, + "2cb26679-2488-4766-9ba2-b35c197e327f": { + "relative_position": [ + 0, + 8 + ], + "visible": false + }, + "6596fb5f-0b16-4f9b-804b-5b8b81db4158": { + "relative_position": [ + 0, + 8 + ], + "visible": false + }, + "8e8dca73-2d11-4631-9c24-5e1a4e3b2920": { + "relative_position": [ + 0, + 8 + ], + "visible": false } }, "connections": {