diff --git a/BEdit/AGENTS.md b/BEdit/AGENTS.md index 82b9a41..460fa21 100644 --- a/BEdit/AGENTS.md +++ b/BEdit/AGENTS.md @@ -60,15 +60,18 @@ Keep the root of `src/bedit` minimal. New UI modules should go into the relevant - Port removal or reorientation must be rejected when it would invalidate an existing connection. - Connections reference port IDs, never port names. -- Graph interaction has separate Pointer and Connect modes. Connections store a - `properties.routing` value (`direct`, `angled`, or `spline`); angled routes - store absolute scene points in `properties.waypoints`. +- Graph interaction has separate Pointer and Connect modes. Port hints are only + visible in Connect mode. Connecting two blocks opens the compatible port-pair + chooser; explicit port clicks determine its default selection. Connections + use one freely angled polyline format with absolute `properties.waypoints`. + Semantic ports choose compatibility, while each rendered endpoint is the + intersection of the owning hitbox and its center-to-adjacent-route-point ray. - Connection appearance is configured per port type in `gui/graphics/connection_styles.py`, including color, width, pen style, and source/target arrowheads. Do not scatter those constants through painters. - Graph annotations are `box`, `line`, or `text` objects in `Graph.annotations`. They use integer layers below or above graph layer 0. Annotation lines reuse - connection routing and absolute `properties.waypoints` semantics. Graph + connection polyline and absolute `properties.waypoints` semantics. Graph annotations and icon elements share `ShapeOptionsDialog` and `shape_pen` so their style fields and rendering must remain aligned. - Icon editing uses a fixed 128×128 coordinate space. diff --git a/BEdit/README.md b/BEdit/README.md index 29fba35..794e7e8 100644 --- a/BEdit/README.md +++ b/BEdit/README.md @@ -110,17 +110,19 @@ BEdit document used as a copy source. The built-in example defines A, B, and C. - Components, interface terminals, and connections are selectable. Use a rubber band or Ctrl-click for multiple selection, Delete to remove items, and the standard Cut/Copy/Paste shortcuts to duplicate selected component groups. -- Switch the graph header to **Connect**, choose Direct, Angled, or Spline, then - click an output and input. Angled connections accept intermediate corner - clicks, use right-angle segments, and snap to the graph snapping grid. - Right-click cancels an unfinished connection. +- Switch the graph header to **Connect** and click two blocks or their temporary + port hints. A chooser lists every compatible output/input pairing in both + directions and preselects the pairing implied by the clicks. Empty-canvas + clicks add freely angled, grid-snapped vertices; right-click cancels. - Select a routed connection to reveal its draggable nodes. Right-click a line - to add a node, or right-click a node to delete it. Angled routes persist every - orthogonal corner as a draggable, grid-snapped node. + to add a node, or right-click a node to delete it. Visible wire endpoints are + projected onto each icon's hitbox where the ray from its center toward the + adjacent route point crosses the boundary. Hidden semantic port positions do + not constrain the wire. - Use **Box**, **Line**, and **Text** to add persistent graph annotations. Lines - share the Direct, Angled, and Spline routing controls. Annotation context menus - provide the same shape styling as the icon editor and can move annotations - through integer layers below or above graph layer 0. + use the same freely angled polyline and draggable-node behavior as connections. + Annotation context menus provide the same shape styling as the icon editor and + can move annotations through integer layers below or above graph layer 0. - Double-click a graph component or select it and use **Down** to open its owned subgraph; use **Up** to return. - Graph components show **Pointer**, **Input**, and **Output** tools. Select an diff --git a/BEdit/resources/icons/draw-circle.png b/BEdit/resources/icons/draw-circle.png new file mode 100644 index 0000000..911f767 Binary files /dev/null and b/BEdit/resources/icons/draw-circle.png differ diff --git a/BEdit/resources/icons/draw-ellipse.png b/BEdit/resources/icons/draw-ellipse.png new file mode 100644 index 0000000..e292d52 Binary files /dev/null and b/BEdit/resources/icons/draw-ellipse.png differ diff --git a/BEdit/resources/icons/draw-path.png b/BEdit/resources/icons/draw-path.png new file mode 100644 index 0000000..dffb691 Binary files /dev/null and b/BEdit/resources/icons/draw-path.png differ diff --git a/BEdit/resources/icons/draw-triangle.png b/BEdit/resources/icons/draw-triangle.png new file mode 100644 index 0000000..c806d69 Binary files /dev/null and b/BEdit/resources/icons/draw-triangle.png differ diff --git a/BEdit/resources/icons/network-connect.png b/BEdit/resources/icons/network-connect.png new file mode 100644 index 0000000..4e32020 Binary files /dev/null and b/BEdit/resources/icons/network-connect.png differ diff --git a/BEdit/resources/resources.qrc b/BEdit/resources/resources.qrc index 4e624d3..1bd73f4 100644 --- a/BEdit/resources/resources.qrc +++ b/BEdit/resources/resources.qrc @@ -1,5 +1,10 @@ + icons/draw-triangle.png + icons/draw-ellipse.png + icons/draw-circle.png + icons/draw-path.png + icons/network-connect.png icons/arrow-down.png icons/configure.png icons/arrow-up.png diff --git a/BEdit/resources/resources_rc.py b/BEdit/resources/resources_rc.py index 3752d1e..276b470 100644 --- a/BEdit/resources/resources_rc.py +++ b/BEdit/resources/resources_rc.py @@ -215,6 +215,89 @@ ff\xa6\x5cP`\xb7\xadY\x1b\xde\x8b\xcb\x97/\xc3\ \x80\x90\x84\xfe\x83\xfe\x0fl\x00\x00/\xbf\xf2\xf2\x7f\x9c\ \xfd\x0bVu/\x8d\xbcS'\xfc\x00\x00\x00\x00IE\ ND\xaeB`\x82\ +\x00\x00\x05\x08\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x03\x00\x00\x00D\xa4\x8a\xc6\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x09pHYs\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01B(\ +\x9bx\x00\x00\x00\x07tIME\x07\xd9\x06\x0a\x00\x03\ +\x0a\xd2\xe0H^\x00\x00\x01\xfbPLTE\x00\x00\x00\ +\xa2\xa2\xa6\xa7\xa7\xab\xa8\xa8\xad\xaf\xaf\xb2\xb1\xb1\xb3\xb3\ +\xb3\xb5\xb6\xb6\xbb\xc4\xc4\xc8\xcb\xcb\xcf\xb9\xb9\xbb\xba\xba\ +\xbe\xc4\xc4\xca\xaa\xaa\xb0\xb0\xb0\xb4\xac\xac\xb2\xad\xad\xb2\ +\xcb\xcb\xd1\xbe\xbe\xc3\xc2\xc2\xc6\xa4\xa4\xa8\xad\xad\xb1\xae\ +\xae\xb1\xb5\xb5\xb6\xaf\xaf\xb3\xb0\xb0\xb3\xb4\xb4\xb9\xb4\xb4\ +\xba\xca\xca\xce\xa9\xa9\xad\xb2\xb2\xb6\xa7\xa7\xac\xa8\xa8\xac\ +\xcb\xcb\xcf\xcb\xcb\xd0\xa1\xa1\xa5\xa2\xa2\xa5\xb2\xb2\xb4\xa2\ +\xa2\xa8\xa4\xa4\xa9\xcc\xcc\xd0\x9c\x9c\xa1\x9e\x9e\xa3\xb3\xb3\ +\xb8\xb4\xb4\xb9\xc3\xc3\xc7\xc3\xc3\xc8\xac\xac\xb1\xad\xad\xb2\ +\xa6\xa6\xa9\xc7\xc7\xcc\xc8\xc8\xcc\xb1\xb1\xb3\xad\xad\xaf\x9d\ +\x9d\xa2\x9e\x9e\xa4\xa1\xa1\xa4\xa2\xa2\xa6\xcb\xcb\xcf\xcb\xcb\ +\xd0\x9a\x9a\x9e\x9b\x9b\xa0\xc5\xc5\xc7\xd2\xd2\xd3\xd2\xd2\xd4\ +\xd3\xd3\xd5\xd6\xd6\xd8\xd7\xd7\xd7\xd7\xd7\xd8\xd9\xd9\xdb\xda\ +\xda\xdb\xdc\xdc\xdd\xde\xde\xdf\xdf\xdf\xe1\xe0\xe0\xe1\xe2\xe2\ +\xe2\xe2\xe2\xe3\xe2\xe2\xe4\xe3\xe3\xe4\xe3\xe3\xe5\xe6\xe6\xe7\ +\xec\xec\xed\xed\xed\xee\xee\xee\xef\xef\xef\xf0\xf0\xf0\xf1\xf1\ +\xf1\xf1\x97\x97\x9c\x98\x98\x9e\x99\x99\x9e\x9a\x9a\x9f\xa7\xa7\ +\xaa\xa8\xa8\xab\xab\xab\xad\xab\xab\xae\xac\xac\xaf\xad\xad\xaf\ +\xad\xad\xb0\xae\xae\xb0\xae\xae\xb1\xaf\xaf\xb1\xb0\xb0\xb4\xb1\ +\xb1\xb4\xb3\xb3\xb8\xb5\xb5\xb8\xb7\xb7\xbb\xb8\xb8\xbc\xba\xba\ +\xbc\xbb\xbb\xbd\xbb\xbb\xbe\xbc\xbc\xbe\xbd\xbd\xc2\xbf\xbf\xc2\ +\xbf\xbf\xc4\xc5\xc5\xc7\xc9\xc9\xcd\xcb\xcb\xcf\xcc\xcc\xd0\xcd\ +\xcd\xd0\xce\xce\xd2\xd5\xd5\xd6\xd5\xd5\xd7\xd7\xd7\xd7\xd7\xd7\ +\xd9\xdb\xdb\xdd\xe0\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\ +\xe3\xe3\xe3\xe4\xe4\xe3\xe4\xe4\xe4\xe4\xe4\xe5\xe5\xe5\xe5\xe6\ +\xe6\xe6\xe7\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xea\xea\ +\xea\xeb\xeb\xea\xeb\xeb\xeb\xeb\xeb\xec\xec\xec\xea\xec\xec\xec\ +\xec\xec\xed\xed\xed\xec\xed\xed\xed\xed\xed\xee\xee\xee\xee\xef\ +\xef\xee\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf2\xf2\ +\xf2\xf3\xf3\xf3\xf4\xf4\xf4\xf5\xf5\xf5\xf6\xf6\xf6\xf7\xf7\xf7\ +\xf8\xf8\xf8\xf9\xf9\xf9\xfa\xfa\xfa\xfb\xfb\xfb\xfc\xfc\xfc\xfd\ +\xfd\xfd\xfe\xfe\xfe\xff\xff\xffN\x89\xad\xb6\x00\x00\x00W\ +tRNS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x17\ +\x18+2668<w\xee\xdc\x19c\x1a4M\x223\x95\x8cj\x91\ +\x8bVE\x9b \x08!\xa1E\xabh\xd3\xbf\xd6\xa6\x82\ +6-\x0c{\xd9\x19\xb5\x09\x82\xa8\xb0\xec\x05\x99A/\ +5\xf9\x92\xe9tg~\xcf\xd39\x00\x00\x00\x00\x00`\ +\x03`\x03\x003\x00,N\xae\x1f}\xd9\xd7{\xab\xdb\ +\x0f\x01\x08`\xb1\xff\xe4\x89\xd7\xd7\x16\xf3\xb5i\xb5?\ +\x1d|\xb9\xdcY\xec\x03\x0d\xb0x\xf6\xad\xe9\xa5\xcd5\ +\xd3\xc8l\xb6\xf8\xf3\xb5\x7f\xef\xae\x80\x06\x1c{o\xf5\ +\xea\x99>j\x0a\x19\xfd\xa9G\xfez\xe3\x97\x87 \xe0\ +\xe8\xbb7\xde<\x9c\xf4>M&m^\xdd\x17O\xbf\ +\xff74\xac/\xde\xb9y\xa9\xc7\x88^css\xa6\ +s\xfa\xdbW~\xac\x89\x86\xe9|{{\x182Ff\ +\x1b\x12r\xd8\xce\x5c\x9d\xdfD\xc3\x13\x97.va\xa4\ +\xcf\x9b\xf4\x8c\x8c\xb8w\xea\xe4\xee?\x14\x8e\xef\x8c*\ +\xa92\x97\x91\xeaE\xdd\x9f\xfcp\x1cM\xdb\xbax1\ +\xc2H\x8d0\x92^\xfd\xc1\x8a3[\xbf\x1e\x8c2m\ +o#\xa9\xaa$#\xa1\xba\xc3V\xe9G\xb6'\xc5\xfa\ +I\x92J\xabdDF\xd4~\xa92_\xa7\xd8~\x0c\ +R\x92\xaa\x18\x91\xc3\x9eD\xd6\xb6)\xce6\x88$ \ +\x1cH\xa5j\xe3\x1c\xc5\x00\xaaR\xa9$LSI\xa5\ +2(v'0\x12I!\xbd)I\xfe\xdb\xa1\xd8[\ +\x82\xa4\xaa\x221zk\xa2\xb2\xda\xa3X}\x02\x88T\ +*Q\x9aJ\xea\xea\x8a\x92\xbb\xcf\x00FE%\x86\xd2\ +\x94\x8dsw\xa2\xf1`~\xe3\xf9@\x92a\xd0\x8d\xf4\ +\x1a\xae\xec\xfeLa\xf7D\x00\x92JR\xa5iGN\ +\xef\xa0\xe1\xdet\xfd\x02 b\x18\xe9\xc9\xec\xa3\xdf\xaf\ +\xa1P\xd7\x8f}<@\x92H\x952\xbb|\xeaz\xa1\ +a\xacn\xbd\xf0\xfds\x80\x11]\xd4\xe5cWn\x0f\ +4\xf0\xe0\xd6\xf9o^\x1c\x81\x0c\x8c\xf6\xc1\x89\xcf\x97\ +\xa0\x01\xf7\xff\xd8\xb0\xb5@b\xd4ly\xed\xb7\xaf\xf6\ +\x80\x06\x98vn.\x96\x9f\x9d\x9dG\xbf\xf3\xe1\xfe\xf2\ +\xd3\x9f\xa6\x0e\x04`\xed\xc0\xe3[\x8f^8\xac\xfa\xee\ +\xee\xbd\xa5\xb5\x03\x00\x00\xcc\xb1\xb9\x899\x00\x00\x00\x00\ +\x00\xfc\x0f\x04u\xc6)\xe3{\x06,\x00\x00\x00\x00I\ +END\xaeB`\x82\ \x00\x00\x08h\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -520,6 +603,142 @@ K,~\x0d\x01\x02\xc2\x08\xa0\x0d\x98$\xc1\xd4\xe8C\ S\xa0\x81ahl}\xb5P\xd4\xd7\xb8\xe9z\x86\x0e\ >L\x06\x80\x01`\xc7\x01\x7f\x03\xdc\xff\x15WD\x01\ nd\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x03o\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\ +\x00\x00\x00\x09pHYs\x00\x00\x03v\x00\x00\x03v\ +\x01}\xd5\x82\xcc\x00\x00\x00\x19tEXtSof\ +tware\x00www.inksca\ +pe.org\x9b\xee<\x1a\x00\x00\x02\xecID\ +ATx\xda\xed\x97\xddN\x1aA\x14\xc7gvfw\ +\xd9E\x10\x10\x95\xa47\xc6\xe2\x17\x9aX\xb7\x8am\xb5\ +\xe5\xda\xcb\xbeP\x13_\xc3X\xa9R\x04\xa5\xd6\xa8\xa5\ +j\x9b\x18\xb0I\xfb\x16\xbe\x81\xbdjb\xaa\xecN\xcf\ +\x0c\xccB\xd8\xc6H\x01\xe9\x85'9\xcc\xecY\xc2\xff\ +w>2\xcbb\xc6\x18\xea\xa5)\xe0\x0f\x00\xff\x17\xc0\ +\xc9\xc9\xe9\xce\xf1\xf1\xd7T\xcf\x00l\xdbYB\xc8Y\ +?::N\xf5\xac\x05cc\x8f\x0dJ\x15\x01q\xdf\ +\x00\x98\x7f\x04\x83\xc1\x1a\x04^?<\xfc\xfc\xea\xbe[\ +\x800\xc6\x02\x22\x1e\x8f\x1b\x8a\x82\xdf\x1e\x1c\x14_\xde\ +7\x80\xf0\xfe\xfe \x1a\x1f\x8f\x1b\xb0\xdd\xd8\xdf\xff\xb4\ +\xdcu\x80\xd5\xd5U\xcc\x98\x00p=\x14\xeaG\x93\x93\ +\xe3\x00\xc1\xd2\x85\xc2\xfer\xd7+\xc0\xc0`\xf1@L\ +MM\x18\x84\x90\x8d\xdd\xdd\x8fK]\x05p\x9cj\x05\ +\x9a!\xc2\xe1\x10\x9a\x9e\x9e0\x09\xc1\xe9|\xfe\xc3\x8b\ +\xae\x00$\x12\x09l\xdb\xcc\x15\xf5B\x84\x01\x22\x01\x10\ +\xca\xbbB\xa1\xf0\xbcK-\xb0\x1bD\xbd\x10\x91H\x18\ +\xcd\xcc$L\xdb\xc6\x9b\xb9\x1c@t\xbe\x05\x02\xe0V\ +\x88XlX\x9b\x9f\x9f\x0b0\x866\xb3\xd9\x9dg\x1d\ +\x03\x18\x1c\x1c\x84\x16\xa0\xfa\x10z!\xb0\xae\xeb>\x15\ +lxx\xc8W\x85`[\x99L~\xb1#\x00\xe5r\ +u\x08)\xa5\x9e\xac\x094\x9e\x8b+`\xbcS\xdcc\ +\xb1!}aa\xae\x8f1'\x93Ng\x16;4\x03\ +\x0e\xe2\x1a\x8d\x10\xb4j\xba\xb8\xdf`\x00{\x03\x83\xe9\ +X\xd6\x13\x13c%\xb3\xb6\x06\x10\xed\x00\xa4R\x5c\x00\ +\x09\x00\x09A\xc0`O\xb96\xc08\xdc\xf9\xa8\xd8\xb6\ +}]\xa9Tn\xe0\x1aZ7\x80\x92I\xcb4M5\ +\xb3\xb5\xb5\x9dl\xab\x02\xd0^.*\x00\xb86@\x10\ +\x08\x0ba\x998\x08_C\xf6\xb6l\x0f\xff\xee\xc0@\ +\x04Y\xd6\xac\xa9i\xfa{\x18\xcc\x85v\x00d\xf6\x98\ +\x80\xf1\xcc\xe1Z(\xd72\xaf\xf0\x98\x1c\xccf\x88\xd9\ +\xd9\x19\xd3\xe7\xd3\xb3\xf9\xfc\xe1|\xcb\x00\x81@\x00S\ +\xaarA\x84\xab\xc6\xa4C\xcc\xa9e\xcd\xa4\xe8\xdf \ +\x22\x91\x10?\xac\x00\x82f\xf7\xf6\x00\xa2\xf5\x0a\x10\xb1\ +rA\xeeP\x09\xbe\x8a\x16@A\x98\x14\xbc\x0d\x22\x1c\ +\xe6\xcf\x8e1\xbfa\xe8\xd9b\xf1\xcb\xd3\x96\x00\xa0\x02\ +|\x91\x102{\xe1r0\xef\x02\x11\x0a\x89?5~\ +J\xc9\xf6\xe9\xe9\x99u'\x80\x8b\x8b\x0b,*P7\ +W\x5c\x0ef+\x10\xc1`\x00\x8d\x8e\x8e\x00\x84\x9a;\ +;\xfbf\xdd\xa9\x02\x84\xd0\xe6\x90+\xfco\x10}h\ +d\xe4\x91_U\x95\xdc\xf9\xf9\x8f9O\xc5\x9b\x8eb\ +\xe8\xb7\xf6\xab\x5c\xfe\xeeW>\xfejdd$\x19\x18\x18\ +\x80\x17\x86\xc6\x02\x7f\xd4}\xe5\x84\xc7\xe9~r\xf8L\ +?i\x802\x99UUU$..N\xde\xfa\x0b\xf0\ +Gu\xd7\x12\x1a\xfa\x08\xfb\xe6\xd7b\xc7\xdb\xdf\x92m\ +\xa0\x1az\x04%\x07\xef\xf7\x82\x82\x02\xf9\xc1\xf3\x8c*\ +P\x8a\xb7 @\x9d\xcc9\x1d\x1d\x8d\xbb\xd9\x22\xce\ +\xee\x98\x00\xf5Vv \xd6\xf0Ffffdww\ +7#k\xbd\x95F\x82R\x95]\xf6G\xaan\xfe\xd9\ +\x0e\xaa\xea\xc6\x22\x14\x0a)))!\xe9\xe9\xe9\xf2\x83\ +\xb7\x04\xa5J[\xc6\xf0\xf2\xb5\x85\xe4\xf2\xeb\x0b7A\ +\x9d\xf8l\x0eJm\xdf\xbe\xfd\xcb\xea\xeaj\xb7J\xa5\ +\x92\xef\xbd\x19JX>\x19\xc1\xd1K\x93\xea#m\x13\ +\xbf\x80:vy\x0aJXU*P\x99\xd5V\xab\xe7\ +\xbe\x97\xaf~\x18\xfe8\xd42\xd6_\xda6\x11U\xda\ +:\x06\x7fT\xc6\xc4,\x1f-,\xf4\x14$\xb2<\x0c\ +\x1fT\xf0r\xa0\xe9\x07ht\xfa,^\x10\x86\xaf\x94\ +=4\x07?\x94\xb3\xac5G\xa7\xd3%\xcd\xcc@m\ +0\xe0\xfc\xfc\x83\x83\x83\ +\xe3\xb5\xa2\xd8\x0a\x0f?; \x09\x1c\xa7\x85B\x06\x83\ +\xe1u5\xcb\x92\x17\x87\x86t\xfbGF\x9c,\xcf\xaf\ +\xdc\x9b\x9cd\x86\xef\xde-ldY\xf8m\xd7K\x1d\ +=I\xc7\xdb\xcd;\x0e7C\x01&77\x97\x18\x8d\ +\xc6\xfb\x1e6)*U\x1bd\x94w\x80\xe7z\x04\xce\ +\xf9\xcch\xeb\x11(PNo==\xfd\xa1\xc3\xe1\x98\x92$\xe9I\x00\ +\xd6\x0dM\xc0d21\xf0\x8c\xfb\xf2\x98\x99K\xaf\x22\ +\x83\xf9~\xd8\xf1s\x83\x8a\xe3%\xb7\x9d\x13\xe7\xb6d\ +\xd5v\x0ab\xf0\x81\xd0\x9c\xba P\x8d'k\xa25\ +\x1a\xcd\x14\xfd\xdd\xb6\xc4\xc4\xc4El\x84\xe7\xaf\x04*\ +//\xef\xfeq\xef\xdf\xdf?\x9b\xb7\x9b\xe0\xd1w\x1b\ +\x9e\xdf\xf7\x14\xc1\xe3u\x04\xe9V\xdb\xf1S\x1f_\xc5\ +\xbf\xc9\xd3\x01\x9f\xa3\x0f\x17Z/\xe3\x7f\xe1/\x17\x85\ +\xd6\x06q(\x0e\x10\x00\x00\x00\x00IEND\xaeB\ +`\x82\ \x00\x00\x02V\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -1210,6 +1429,113 @@ G%\xc7A \x00\x1d\xd0\x80I\xe0\x03\x10;3\x85\ \xfaS\x08V\x01()\xc7\xe4\xb9C\x95,\x01\xd77\ \x9aw\xed\x7f\xefoJ\x88l\x9a\x02\xc2\xbb\x00\x00\x00\ \x00\x00IEND\xaeB`\x82\ +\x00\x00\x06\x8f\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\ +\x00\x00\x00\x09pHYs\x00\x00\x03v\x00\x00\x03v\ +\x01}\xd5\x82\xcc\x00\x00\x00\x19tEXtSof\ +tware\x00www.inksca\ +pe.org\x9b\xee<\x1a\x00\x00\x06\x0cID\ +ATx\xda\xddWYLUW\x14=NiSQ\ +\x8b\xad\xb1\xad\x16\x8d\x1dR\xd39\xa6\xa6\x95\xb6Im\ +b\xda\xaf\xfe\xe0w\xd3~\x01%6V\x1cA\x8b\x8a\ +\x10)NLB\xa1\x10@\x85\x08\x05\xc2P\xa8\x81\xfa\ +\xe1\x00\xca\xa48\x81\xa2(\x93\x82\x82\xcc\xd3\xe3\x9d\xdd\ +\xb5N^o.\x06\x1b\xb0$&}\xc9\x0a\xbcs\xef\ +;{\xed\xbd\xd7\xdeg\x1f%\x22O\x15\xff/\x02\xf8\ +L\x0b\x0a\x0ar{*\x046n\xdc\xf8Ahhh\ +[zz\xfahHHH*\x88\xcc|\xf4\x9d\x83\x07\ +\x0f.\xf2\xf6\xf6\x0e^\xb5j\xd5\xb7nnn\xeeS\ +F`\xd3\xa6M\xcb\xf7\xed\xdb\xd7WYY)W\xaf\ +^\x95K\x97.i\x18\xabpEczuu\xf5G\ +\x87\x0e\x1d\xfa\x04k\xad>>>G===W\xcc\ +\x993gj\x08l\xd9\xb2\xe5\xf5\xb0\xb0\xb0\xee\x0b\x17\ +.\xc8\xe5\xcb\x97\xa5\xa6\xa6Fjkk\xe5\xc6\x8d\x1b\ +:>>\xbe\xbd\xb4\xb4\xb4\x0c\xebCg\xce\x9c\x19\x01\ +\x89R___\xf7)K\xc1\x86\x0d\x1b\x96\xec\xdd\xbb\ +\xb7\x83F\xeb\xea\xea\xe4\xc1\x83\x07RUU%\xf0X\ +\xea\xeb\xeb\xe5\xf6\xed\xdb\x92\x96\x96\xa6\xcf\x9f?/\xd7\ +\xaf_\x97k\xd7\xae\x05N\x95\x06\x18\xf6W\x90\xf3v\ +\x84[n\xde\xbci\x0c\xb6\xb6\xb6Jww\xb70\x1a\ +$u\xeb\xd6-\xae\x19\x12\x88Joss\xf3\xe2)\ +!\xb0u\xeb\xd6\x05{\xf6\xeci\xb9r\xe5\x8a\xdc\xb9\ +s\x87\xde\x1b\x83\x0d\x0d\x0d\xd2\xde\xden\x91\xf8\xe7y\ +cc\xa3NHH\xe8\x1cO\x98O\x92s\xf7\xdd\xbb\ +w7 \x9c\x1a\x1e\x19\x0f\x07\x07\x07\x19^\x8a\x8f\x06\ +\x99\x0aC\xe2\xe2\xc5\x8bF\x0fMMM\xd4\x84\x13\xa4\ +S\xff\x13\x01z\xb0k\xd7\xaeZ(]\xdf\xbd{\xd7\ +\x0aqGG\x07I\xd0\x98\xf1\x9a\xc4\x1e>|H\x12\ +\x8c\x0c\xf3\xcf\xf7\x18\x95\xd1\x80\x80\x80\x1f\x9e\x98\xc0\xe6\ +\xcd\x9b\xbf\xce\xcd\xcd\x1d\xbe\x7f\xff\xbe\xf4\xf5\xf51\xb4\ +F\xf9mmm4h\x91\x00,=\xf4\xf4\xf4Xz\ +\xe0zjj\xea\xc0\xda\xb5kgL\x86\x00=\x9f\xbe\ +m\xdb\xb6H\xd4\xf1pdd\xa4\x93\xb5\xce\xcd\x1d\x0e\ +\x87\x09/\xbf\x83\x14\xd7H\x82\x9a`\xc8I\x8cD\xcd\ +:{\xc4\xe9\xd3\xa7%11q\x88\xfbM\x98\x00\xdb\ +\xeb\xf6\xed\xdb\xd3\xa1r\xa7\xe0\x93\x94\x94$qqq\ +\x9a\xf9\xee\xed\xed\xb5H\xd0\xbb\xce\xceN\xb3644\ +\xc4\xb0\xd3k\x920d\xd0\x07$##\xc3\x89\xea\xf9\ +~R)\x80\xe7\xbf\xc1\xc3Q|\xe4\xde\xbd{\xc6\xa3\ +\xa8\xa8(\x1d\x1b\x1b\xabY\xef\x03\x03\x03\x16\x09\x1a\xea\ +\xea\xea\x92\xfe\xfe~\x92\xa00\x99\x22\xe3yff\xa6\ +\x13)\xfciR\x22\x84`\x22(\x1cnF#$A\ +\xcf\xe8exx\xb8\x8e\x89\x89\xd1\x0c-\xc3\xceg\x14\ +\x1f\xbd\xe6s\x86\x9d\xbd\xe1\xd4\xa9S\x92\x95\x95\xa5Q\ +\xba?O\xea0\xc2\x0fB\xce\x9d;\xe7\xa0\xc7\x14\x12\ +=\xa5\x91\x91\x91\x11\xe6\xd8D\x03\x15\xa1\xa1\x09]V\ +V\xc6u\x8b\x04\x1b\x13SB\xcf\xb3\xb3\xb3u``\ +`\xd8dNC\xd6z\x00\x98;l\xa2b.\xe9\x19\ +\x8dX\xe1\xa5!DI\xa3\xc7\xeb\xb3g\xcf2J$\ +\xcbr3\x9e\xe7\xe4\xe4\xe8\x1d;v\x1c\xb6\x8c\xc5\xa9\ +Y*Je\x02_>\x8e\x00\x8f\xd5\x1fKJJ\x1c\ +\x14\x14@\xcf\xad\xf2\xa2\xd74@\x12\x5c\xa7\xfaYb\ +\xf8\x8d\xde\xbf\x7f\xbf.**\x221\xcb8\xc4{\xc4\ +2t\x5c\xcdP\xb1*\x03\x10\xa0O\x1dV\x9e\x5c\x7f\ +\xb4\xbf\x7fWXX8\xc2\x92b[%\xd8\xd5h\x8c\ +\xc2\xa2A6 \x0a\x8d$\x18\x11V\x03N\xa1\x8b\x09gt\xce\xea\x9c\xd99\xbbs\x86\xe7,\ +\xcf\x99\x9e\xb3=\xaa\xa3\x9c$0RIrr\xb2D\ +DD\x0c\xf2.`\xdf\xc84\x9b\x22\x95\xa4\xfeT\x02\ +\x0c\xa9\x13j\xcd\x84oF\xbc\xa5\xf0\xb6\xc2[\x0bo\ +/\xe3\x09\x13\x06S\x00'\xdak'oA\xe3n\x16\ +\xa4\xa6\xab\x12\x95\xaa\xfeR\xdf<\xd1\xd5\x0c\x9f\x99\xc0\ +s\xc0<\xe0E\xe0e\xc0\x03X\x06\xbc\xe9\xe1\xe1\xb1\ +\x02\x7f\xdf\x01\xde\x05\xde\xb3\x81\xdf\xdf\x06\x96\xf3=\xe0\ +5`)\xf0*\xf0\x12\xb0\x00x\x1ep\x03\x9e\x01\xc6\ +\x8ed\xec\xd9\x5c\x04\x9e\x05\xe6\x02/\xb8\x8c/\x01\xde\ +pm\xfe!\xf01\xf0\x19\xb0\x1aX\x03|\xe5\xfa\xfb\ +\x05\xf0)\xb0\x92\xef\xf1}\x12q\x91X\x04,\x04\xe6\ +so\x97\x8dY\x80i\xd5\x7f\x03\x81\xe3\xecT\x9c\xdf\ +M_\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x06\xf7\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -1739,6 +2065,76 @@ K\x80@\x89\x15\x8d\xc04\xd5\xb5^\xaf\x1bx\xfa\x19\ \x84\xe7\x04\xcf\x88\xfd\xfd\xfd\xe4\xe8\xe8\xc8\x9dL&\x14\ \xc7\xcc\x7f5p\xf2g\x94\xf7\x1f\xdf\x9a\xd2\x93\xfbC\ \xb7\xa7\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x04<\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\ +\x00\x00\x09pHYs\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\ +B(\x9bx\x00\x00\x00\x07tIME\x07\xd9\x06\x0a\ +\x00\x09%\x83\xde\x9d\x8d\x00\x00\x03\xbcIDATx\ +\xda\xedV\xcdKTQ\x14\xbfw\xe6\xcdG\xcf)\xc6\ +\x19B\xc5\x8a\x1aE\x86\xa4\x85\x91!\x13\x99\x8b(\x0d\ +\x94\xc12\x93\x04\xc9\x16m\x82P\xe8\x0f\x88v-l\ +\x1bA\xad\x22RC\xcbA\xa6,\xa5\x19\xd0\x81\xc6>\ +\x16-\xc2\x92 \x0cc2\xc7\xf2c\x9c\xcf\xdb9\xd1\ +y\xbc\xde\xbc)\xc6 \x10\xe6\x07\x87{\xdf\xbc;\xe7\ +\xf7;\xe7\xdc{\xeec\x05\x14\xb0\xa9\x10\x0e\xbf\xfa\xe7\ +5Z\xf0<\xc8w\xc0\xd0$\x84h\xe0\x9c\xef\x87\xb9\ +\x13l;\x98\x00\xfb\x02\xf6\x15\xdeM\xc3\xbbg0\xf7\ +\xd7\xd6\xd6\xccOM=g\x1e\xcf\xc1\x8d\x09\x08\x04&\ +\xd9\x91#\x87X(4}.\x93I\xf5\x18\x8d\xd2\xbe\ +m\xdb\xb62Y\xb6\x0a\xab\xd5\xcc\x8dF#\x032\x06\ +\xa4,\x9dN\xb3D\x22\xc5\xd6\xd7\xe3\x02\x8c\xc7bk\ +,\x99\xcc\xbc2\x18\x0c}\x1eO\xed\x1d\xf2\x95\x97\x80\ +`p\xca\x93J\xa5\xee\xdb\xed\xf6\xb2\xd2\xd2\xed\xc2f\ ++\xe2\xf0\x8c\x84\x8a!p\xccd28*s\x14\x86\ +b\xbe\x7f_\xe6\xd1\xe8\xb7\x8f\x92$\x9d\xac\xaf\xf7L\ +\xeb\xf1\x18\xd4\x0f~\xffS\x86\x98\x98\x08^\x81\xa8&\ +\xab\xab\xdd\xa5nw%+*\x9299V\x1b\x01\xe7\ +@\xc2,\x16\x0b\xb3\xd9l\xb0\xbe\x889\x9d\x0e\xeer\ +\xedfUU\x15;\xc1Wx|?\xff\x19\xdb\xf0;I2\xf7\ +\xb5\xb4\x9c\xb8A\xbe6\xfaIF7\xa5[\x88\xccq\ +\xa0k\x00\xc2\x1a\xfc\x1c\x83h\xe5_%Y\xc1\xa0a\ +|\x01\x85\x09\x800\x7fss\xd3{\xf6\x7fABG\ +Y\x01\x05l*\xfc\x00!\x00\x12\xf1%U\xb6\x0e\x00\ +\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x02\x92\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -1875,6 +2271,10 @@ qt_resource_name = b"\ \x00z\ \x00o\x00o\x00m\x00-\x00o\x00r\x00i\x00g\x00i\x00n\x00a\x00l\x00.\x00p\x00n\x00g\ \ +\x00\x0f\ +\x0bb\xb8g\ +\x00d\ +\x00r\x00a\x00w\x00-\x00c\x00i\x00r\x00c\x00l\x00e\x00.\x00p\x00n\x00g\ \x00\x14\ \x0b\xa9\xab'\ \x00d\ @@ -1889,6 +2289,15 @@ qt_resource_name = b"\ \x09\xd0z\x07\ \x00a\ \x00r\x00r\x00o\x00w\x00-\x00u\x00p\x00.\x00p\x00n\x00g\ +\x00\x11\ +\x06\xfb\x85G\ +\x00d\ +\x00r\x00a\x00w\x00-\x00t\x00r\x00i\x00a\x00n\x00g\x00l\x00e\x00.\x00p\x00n\x00g\ +\ +\x00\x0d\ +\x0f\xba\x1e'\ +\x00d\ +\x00r\x00a\x00w\x00-\x00p\x00a\x00t\x00h\x00.\x00p\x00n\x00g\ \x00\x0d\ \x0b\xe6\x1f\xa7\ \x00d\ @@ -1922,6 +2331,11 @@ qt_resource_name = b"\ \x00d\ \x00r\x00a\x00w\x00-\x00b\x00e\x00z\x00i\x00e\x00r\x00-\x00c\x00u\x00r\x00v\x00e\ \x00s\x00.\x00p\x00n\x00g\ +\x00\x13\ +\x04\xc4\x04G\ +\x00n\ +\x00e\x00t\x00w\x00o\x00r\x00k\x00-\x00c\x00o\x00n\x00n\x00e\x00c\x00t\x00.\x00p\ +\x00n\x00g\ \x00\x0c\ \x06\xeb\x97\xe7\ \x00z\ @@ -1948,6 +2362,10 @@ qt_resource_name = b"\ \x00d\ \x00o\x00c\x00u\x00m\x00e\x00n\x00t\x00-\x00s\x00a\x00v\x00e\x00.\x00p\x00n\x00g\ \ +\x00\x10\ +\x03\xe6\xd3g\ +\x00d\ +\x00r\x00a\x00w\x00-\x00e\x00l\x00l\x00i\x00p\x00s\x00e\x00.\x00p\x00n\x00g\ \x00\x12\ \x09\xb3>\xc7\ \x00d\ @@ -1965,49 +2383,59 @@ qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1a\x00\x00\x00\x03\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x01r\x00\x00\x00\x00\x00\x01\x00\x00:\x16\ +\x00\x00\x01\xde\x00\x00\x00\x00\x00\x01\x00\x00G\x5c\ \x00\x00\x01\x9f{C\xf1'\ -\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00Pr\ +\x00\x00\x02\x9a\x00\x00\x00\x00\x00\x01\x00\x00dK\ \x00\x00\x01\x9f{0\xc99\ -\x00\x00\x018\x00\x00\x00\x00\x00\x01\x00\x00/`\ +\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x00<\xa6\ \x00\x00\x01\x9f\x7f&\x83\xcd\ -\x00\x00\x01\x18\x00\x00\x00\x00\x00\x01\x00\x00'x\ +\x00\x00\x01\x84\x00\x00\x00\x00\x00\x01\x00\x004\xbe\ \x00\x00\x01\x9f{C\xf1\x18\ -\x00\x00\x02p\x00\x00\x00\x00\x00\x01\x00\x00`\xe1\ +\x00\x00\x03R\x00\x00\x00\x00\x00\x01\x00\x00}\x9f\ +\x00\x00\x01\x9f\x7fY\xceg\ +\x00\x00\x02P\x00\x00\x00\x00\x00\x01\x00\x00V\xbd\ +\x00\x00\x01\x9f\x7fV\xd5\xc0\ +\x00\x00\x03\x08\x00\x00\x00\x00\x00\x01\x00\x00t\xba\ \x00\x00\x01\x9f\x7f&\x83r\ -\x00\x00\x01\xe4\x00\x00\x00\x00\x00\x01\x00\x00Iw\ +\x00\x00\x02|\x00\x00\x00\x00\x00\x01\x00\x00]P\ \x00\x00\x01\x9f\x7f&\x83\xb1\ -\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x006\x96\ +\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x01\x00\x00$|\ +\x00\x00\x01\x9f\x7fY\xce\x82\ +\x00\x00\x01\xc0\x00\x00\x00\x00\x00\x01\x00\x00C\xdc\ \x00\x00\x01\x9f{C\xf1.\ -\x00\x00\x00\xf8\x00\x00\x00\x00\x00\x01\x00\x00!\xca\ +\x00\x00\x01d\x00\x00\x00\x00\x00\x01\x00\x00/\x10\ \x00\x00\x01\x9f{{\xa5\xd5\ -\x00\x00\x02\xba\x00\x00\x00\x00\x00\x01\x00\x00i\xc6\ +\x00\x00\x03x\x00\x00\x00\x00\x00\x01\x00\x00\x81\xdf\ \x00\x00\x01\x9f\x7f&\x83\x10\ -\x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x1b\xcd\ +\x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00 \xd9\ \x00\x00\x01\x9f\x7f&\x83~\ -\x00\x00\x02L\x00\x00\x00\x00\x00\x01\x00\x00\x5c\xfe\ +\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x00p\xd7\ \x00\x00\x01\x9f\x7f&\x83T\ \x00\x00\x00^\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xc1\ +\x00\x00\x01\x9f\x7fY\xce^\ +\x00\x00\x00\x82\x00\x00\x00\x00\x00\x01\x00\x00\x11\xcd\ \x00\x00\x01\x9f{0\xc9B\ -\x00\x00\x00\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x1fp\ +\x00\x00\x01D\x00\x00\x00\x00\x00\x01\x00\x00,\xb6\ \x00\x00\x01\x9f\x7f&\x83)\ -\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x00W|\ +\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x00kU\ \x00\x00\x01\x9f{C\xf1N\ -\x00\x00\x01\xb2\x00\x00\x00\x00\x00\x01\x00\x00EH\ +\x00\x00\x02\x1e\x00\x00\x00\x00\x00\x01\x00\x00R\x8e\ \x00\x00\x01\x9f\x7f&\x82\xf2\ -\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x15-\ +\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x1a9\ \x00\x00\x01\x9f{\x8d\xf34\ \x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ \x00\x00\x01\x9f{0\xc9+\ -\x00\x00\x01\x92\x00\x00\x00\x00\x00\x01\x00\x00=v\ +\x00\x00\x01\xfe\x00\x00\x00\x00\x00\x01\x00\x00J\xbc\ \x00\x00\x01\x9f{C\xf1=\ \x00\x00\x006\x00\x00\x00\x00\x00\x01\x00\x00\x05\x86\ \x00\x00\x01\x9f\x7f&\x83\x99\ -\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x00l\x5c\ +\x00\x00\x03\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x84u\ \x00\x00\x01\x9f{{\xa5\xe3\ -\x00\x00\x02\x92\x00\x00\x00\x00\x00\x01\x00\x00d\xd3\ +\x00\x00\x01$\x00\x00\x00\x00\x00\x01\x00\x00'\xef\ +\x00\x00\x01\x9f\x7fV\xd5\xe5\ +\x00\x00\x03*\x00\x00\x00\x00\x00\x01\x00\x00x\xac\ \x00\x00\x01\x9f{0\xc9R\ " diff --git a/BEdit/src/bedit/gui/controllers/document.py b/BEdit/src/bedit/gui/controllers/document.py index 12f3120..5fc1a7f 100644 --- a/BEdit/src/bedit/gui/controllers/document.py +++ b/BEdit/src/bedit/gui/controllers/document.py @@ -235,7 +235,6 @@ class DocumentController(QObject): source: Endpoint, target: Endpoint, *, - routing: str = "angled", waypoints: list[QPointF] | None = None, ) -> str: if self.active_component_id is None: @@ -246,14 +245,11 @@ class DocumentController(QObject): raise ValueError("A connection endpoint no longer exists") if not PortTypeRegistry.compatible(source_port.type, target_port.type): raise ValueError(f"Cannot connect {source_port.type!r} to {target_port.type!r}") - if routing not in {"direct", "angled", "spline"}: - raise ValueError(f"Unknown connection routing: {routing}") connection = Connection( str(uuid4()), source, target, properties={ - "routing": routing, "waypoints": [{"x": point.x(), "y": point.y()} for point in (waypoints or [])], }, ) @@ -267,7 +263,6 @@ class DocumentController(QObject): end: QPointF, *, text: str = "", - routing: str = "angled", waypoints: list[QPointF] | None = None, ) -> str: if self.active_component_id is None: @@ -297,16 +292,13 @@ class DocumentController(QObject): layer=-1, properties={ **style, - "routing": routing, "waypoints": [{"x": point.x(), "y": point.y()} for point in (waypoints or [])], }, ) self.undo_stack.push(AddAnnotationCommand(self, self.active_component_id, annotation)) return annotation.id - def set_route_waypoints( - self, item_kind: str, item_id: str, waypoints: list[QPointF], routing: str | None = None - ) -> None: + def set_route_waypoints(self, item_kind: str, item_id: str, waypoints: list[QPointF]) -> None: item = ( self.active_graph.connections if item_kind == "connection" @@ -316,8 +308,6 @@ class DocumentController(QObject): return old = deepcopy(item.properties) new = deepcopy(old) - if routing is not None: - new["routing"] = routing new["waypoints"] = [{"x": point.x(), "y": point.y()} for point in waypoints] if old != new: self.undo_stack.push( diff --git a/BEdit/src/bedit/gui/dialogs/connection_chooser.py b/BEdit/src/bedit/gui/dialogs/connection_chooser.py new file mode 100644 index 0000000..f899918 --- /dev/null +++ b/BEdit/src/bedit/gui/dialogs/connection_chooser.py @@ -0,0 +1,18 @@ +from PySide6.QtWidgets import QDialog + +from bedit.gui.generated.ui_connection_chooser_dialog import Ui_ConnectionChooserDialog + + +class ConnectionChooserDialog(QDialog): + def __init__(self, labels: list[str], default_index: int = 0, parent=None) -> None: + super().__init__(parent) + self.ui = Ui_ConnectionChooserDialog() + self.ui.setupUi(self) + self.ui.connectionList.addItems(labels) + if labels: + self.ui.connectionList.setCurrentRow(max(0, min(default_index, len(labels) - 1))) + self.ui.buttonBox.button(self.ui.buttonBox.StandardButton.Ok).setEnabled(bool(labels)) + + @property + def selected_index(self) -> int: + return self.ui.connectionList.currentRow() diff --git a/BEdit/src/bedit/gui/generated/resources_rc.py b/BEdit/src/bedit/gui/generated/resources_rc.py index 3752d1e..276b470 100644 --- a/BEdit/src/bedit/gui/generated/resources_rc.py +++ b/BEdit/src/bedit/gui/generated/resources_rc.py @@ -215,6 +215,89 @@ ff\xa6\x5cP`\xb7\xadY\x1b\xde\x8b\xcb\x97/\xc3\ \x80\x90\x84\xfe\x83\xfe\x0fl\x00\x00/\xbf\xf2\xf2\x7f\x9c\ \xfd\x0bVu/\x8d\xbcS'\xfc\x00\x00\x00\x00IE\ ND\xaeB`\x82\ +\x00\x00\x05\x08\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x03\x00\x00\x00D\xa4\x8a\xc6\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x09pHYs\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01B(\ +\x9bx\x00\x00\x00\x07tIME\x07\xd9\x06\x0a\x00\x03\ +\x0a\xd2\xe0H^\x00\x00\x01\xfbPLTE\x00\x00\x00\ +\xa2\xa2\xa6\xa7\xa7\xab\xa8\xa8\xad\xaf\xaf\xb2\xb1\xb1\xb3\xb3\ +\xb3\xb5\xb6\xb6\xbb\xc4\xc4\xc8\xcb\xcb\xcf\xb9\xb9\xbb\xba\xba\ +\xbe\xc4\xc4\xca\xaa\xaa\xb0\xb0\xb0\xb4\xac\xac\xb2\xad\xad\xb2\ +\xcb\xcb\xd1\xbe\xbe\xc3\xc2\xc2\xc6\xa4\xa4\xa8\xad\xad\xb1\xae\ +\xae\xb1\xb5\xb5\xb6\xaf\xaf\xb3\xb0\xb0\xb3\xb4\xb4\xb9\xb4\xb4\ +\xba\xca\xca\xce\xa9\xa9\xad\xb2\xb2\xb6\xa7\xa7\xac\xa8\xa8\xac\ +\xcb\xcb\xcf\xcb\xcb\xd0\xa1\xa1\xa5\xa2\xa2\xa5\xb2\xb2\xb4\xa2\ +\xa2\xa8\xa4\xa4\xa9\xcc\xcc\xd0\x9c\x9c\xa1\x9e\x9e\xa3\xb3\xb3\ +\xb8\xb4\xb4\xb9\xc3\xc3\xc7\xc3\xc3\xc8\xac\xac\xb1\xad\xad\xb2\ +\xa6\xa6\xa9\xc7\xc7\xcc\xc8\xc8\xcc\xb1\xb1\xb3\xad\xad\xaf\x9d\ +\x9d\xa2\x9e\x9e\xa4\xa1\xa1\xa4\xa2\xa2\xa6\xcb\xcb\xcf\xcb\xcb\ +\xd0\x9a\x9a\x9e\x9b\x9b\xa0\xc5\xc5\xc7\xd2\xd2\xd3\xd2\xd2\xd4\ +\xd3\xd3\xd5\xd6\xd6\xd8\xd7\xd7\xd7\xd7\xd7\xd8\xd9\xd9\xdb\xda\ +\xda\xdb\xdc\xdc\xdd\xde\xde\xdf\xdf\xdf\xe1\xe0\xe0\xe1\xe2\xe2\ +\xe2\xe2\xe2\xe3\xe2\xe2\xe4\xe3\xe3\xe4\xe3\xe3\xe5\xe6\xe6\xe7\ +\xec\xec\xed\xed\xed\xee\xee\xee\xef\xef\xef\xf0\xf0\xf0\xf1\xf1\ +\xf1\xf1\x97\x97\x9c\x98\x98\x9e\x99\x99\x9e\x9a\x9a\x9f\xa7\xa7\ +\xaa\xa8\xa8\xab\xab\xab\xad\xab\xab\xae\xac\xac\xaf\xad\xad\xaf\ +\xad\xad\xb0\xae\xae\xb0\xae\xae\xb1\xaf\xaf\xb1\xb0\xb0\xb4\xb1\ +\xb1\xb4\xb3\xb3\xb8\xb5\xb5\xb8\xb7\xb7\xbb\xb8\xb8\xbc\xba\xba\ +\xbc\xbb\xbb\xbd\xbb\xbb\xbe\xbc\xbc\xbe\xbd\xbd\xc2\xbf\xbf\xc2\ +\xbf\xbf\xc4\xc5\xc5\xc7\xc9\xc9\xcd\xcb\xcb\xcf\xcc\xcc\xd0\xcd\ +\xcd\xd0\xce\xce\xd2\xd5\xd5\xd6\xd5\xd5\xd7\xd7\xd7\xd7\xd7\xd7\ +\xd9\xdb\xdb\xdd\xe0\xe0\xe0\xe0\xe0\xe1\xe1\xe1\xe1\xe2\xe2\xe2\ +\xe3\xe3\xe3\xe4\xe4\xe3\xe4\xe4\xe4\xe4\xe4\xe5\xe5\xe5\xe5\xe6\ +\xe6\xe6\xe7\xe7\xe7\xe7\xe7\xe8\xe8\xe8\xe8\xe9\xe9\xe9\xea\xea\ +\xea\xeb\xeb\xea\xeb\xeb\xeb\xeb\xeb\xec\xec\xec\xea\xec\xec\xec\ +\xec\xec\xed\xed\xed\xec\xed\xed\xed\xed\xed\xee\xee\xee\xee\xef\ +\xef\xee\xef\xef\xef\xef\xef\xf0\xf0\xf0\xf0\xf1\xf1\xf1\xf2\xf2\ +\xf2\xf3\xf3\xf3\xf4\xf4\xf4\xf5\xf5\xf5\xf6\xf6\xf6\xf7\xf7\xf7\ +\xf8\xf8\xf8\xf9\xf9\xf9\xfa\xfa\xfa\xfb\xfb\xfb\xfc\xfc\xfc\xfd\ +\xfd\xfd\xfe\xfe\xfe\xff\xff\xffN\x89\xad\xb6\x00\x00\x00W\ +tRNS\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0d\x17\ +\x18+2668<w\xee\xdc\x19c\x1a4M\x223\x95\x8cj\x91\ +\x8bVE\x9b \x08!\xa1E\xabh\xd3\xbf\xd6\xa6\x82\ +6-\x0c{\xd9\x19\xb5\x09\x82\xa8\xb0\xec\x05\x99A/\ +5\xf9\x92\xe9tg~\xcf\xd39\x00\x00\x00\x00\x00`\ +\x03`\x03\x003\x00,N\xae\x1f}\xd9\xd7{\xab\xdb\ +\x0f\x01\x08`\xb1\xff\xe4\x89\xd7\xd7\x16\xf3\xb5i\xb5?\ +\x1d|\xb9\xdcY\xec\x03\x0d\xb0x\xf6\xad\xe9\xa5\xcd5\ +\xd3\xc8l\xb6\xf8\xf3\xb5\x7f\xef\xae\x80\x06\x1c{o\xf5\ +\xea\x99>j\x0a\x19\xfd\xa9G\xfez\xe3\x97\x87 \xe0\ +\xe8\xbb7\xde<\x9c\xf4>M&m^\xdd\x17O\xbf\ +\xff74\xac/\xde\xb9y\xa9\xc7\x88^css\xa6\ +s\xfa\xdbW~\xac\x89\x86\xe9|{{\x182Ff\ +\x1b\x12r\xd8\xce\x5c\x9d\xdfD\xc3\x13\x97.va\xa4\ +\xcf\x9b\xf4\x8c\x8c\xb8w\xea\xe4\xee?\x14\x8e\xef\x8c*\ +\xa92\x97\x91\xeaE\xdd\x9f\xfcp\x1cM\xdb\xbax1\ +\xc2H\x8d0\x92^\xfd\xc1\x8a3[\xbf\x1e\x8c2m\ +o#\xa9\xaa$#\xa1\xba\xc3V\xe9G\xb6'\xc5\xfa\ +I\x92J\xabdDF\xd4~\xa92_\xa7\xd8~\x0c\ +R\x92\xaa\x18\x91\xc3\x9eD\xd6\xb6)\xce6\x88$ \ +\x1cH\xa5j\xe3\x1c\xc5\x00\xaaR\xa9$LSI\xa5\ +2(v'0\x12I!\xbd)I\xfe\xdb\xa1\xd8[\ +\x82\xa4\xaa\x221zk\xa2\xb2\xda\xa3X}\x02\x88T\ +*Q\x9aJ\xea\xea\x8a\x92\xbb\xcf\x00FE%\x86\xd2\ +\x94\x8dsw\xa2\xf1`~\xe3\xf9@\x92a\xd0\x8d\xf4\ +\x1a\xae\xec\xfeLa\xf7D\x00\x92JR\xa5iGN\ +\xef\xa0\xe1\xdet\xfd\x02 b\x18\xe9\xc9\xec\xa3\xdf\xaf\ +\xa1P\xd7\x8f}<@\x92H\x952\xbb|\xeaz\xa1\ +a\xacn\xbd\xf0\xfds\x80\x11]\xd4\xe5cWn\x0f\ +4\xf0\xe0\xd6\xf9o^\x1c\x81\x0c\x8c\xf6\xc1\x89\xcf\x97\ +\xa0\x01\xf7\xff\xd8\xb0\xb5@b\xd4ly\xed\xb7\xaf\xf6\ +\x80\x06\x98vn.\x96\x9f\x9d\x9dG\xbf\xf3\xe1\xfe\xf2\ +\xd3\x9f\xa6\x0e\x04`\xed\xc0\xe3[\x8f^8\xac\xfa\xee\ +\xee\xbd\xa5\xb5\x03\x00\x00\xcc\xb1\xb9\x899\x00\x00\x00\x00\ +\x00\xfc\x0f\x04u\xc6)\xe3{\x06,\x00\x00\x00\x00I\ +END\xaeB`\x82\ \x00\x00\x08h\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -520,6 +603,142 @@ K,~\x0d\x01\x02\xc2\x08\xa0\x0d\x98$\xc1\xd4\xe8C\ S\xa0\x81ahl}\xb5P\xd4\xd7\xb8\xe9z\x86\x0e\ >L\x06\x80\x01`\xc7\x01\x7f\x03\xdc\xff\x15WD\x01\ nd\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x03o\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\ +\x00\x00\x00\x09pHYs\x00\x00\x03v\x00\x00\x03v\ +\x01}\xd5\x82\xcc\x00\x00\x00\x19tEXtSof\ +tware\x00www.inksca\ +pe.org\x9b\xee<\x1a\x00\x00\x02\xecID\ +ATx\xda\xed\x97\xddN\x1aA\x14\xc7gvfw\ +\xd9E\x10\x10\x95\xa47\xc6\xe2\x17\x9aX\xb7\x8am\xb5\ +\xe5\xda\xcb\xbeP\x13_\xc3X\xa9R\x04\xa5\xd6\xa8\xa5\ +j\x9b\x18\xb0I\xfb\x16\xbe\x81\xbdjb\xaa\xecN\xcf\ +\x0c\xccB\xd8\xc6H\x01\xe9\x85'9\xcc\xecY\xc2\xff\ +w>2\xcbb\xc6\x18\xea\xa5)\xe0\x0f\x00\xff\x17\xc0\ +\xc9\xc9\xe9\xce\xf1\xf1\xd7T\xcf\x00l\xdbYB\xc8Y\ +?::N\xf5\xac\x05cc\x8f\x0dJ\x15\x01q\xdf\ +\x00\x98\x7f\x04\x83\xc1\x1a\x04^?<\xfc\xfc\xea\xbe[\ +\x800\xc6\x02\x22\x1e\x8f\x1b\x8a\x82\xdf\x1e\x1c\x14_\xde\ +7\x80\xf0\xfe\xfe \x1a\x1f\x8f\x1b\xb0\xdd\xd8\xdf\xff\xb4\ +\xdcu\x80\xd5\xd5U\xcc\x98\x00p=\x14\xeaG\x93\x93\ +\xe3\x00\xc1\xd2\x85\xc2\xfer\xd7+\xc0\xc0`\xf1@L\ +MM\x18\x84\x90\x8d\xdd\xdd\x8fK]\x05p\x9cj\x05\ +\x9a!\xc2\xe1\x10\x9a\x9e\x9e0\x09\xc1\xe9|\xfe\xc3\x8b\ +\xae\x00$\x12\x09l\xdb\xcc\x15\xf5B\x84\x01\x22\x01\x10\ +\xca\xbbB\xa1\xf0\xbcK-\xb0\x1bD\xbd\x10\x91H\x18\ +\xcd\xcc$L\xdb\xc6\x9b\xb9\x1c@t\xbe\x05\x02\xe0V\ +\x88XlX\x9b\x9f\x9f\x0b0\x866\xb3\xd9\x9dg\x1d\ +\x03\x18\x1c\x1c\x84\x16\xa0\xfa\x10z!\xb0\xae\xeb>\x15\ +lxx\xc8W\x85`[\x99L~\xb1#\x00\xe5r\ +u\x08)\xa5\x9e\xac\x094\x9e\x8b+`\xbcS\xdcc\ +\xb1!}aa\xae\x8f1'\x93Ng\x16;4\x03\ +\x0e\xe2\x1a\x8d\x10\xb4j\xba\xb8\xdf`\x00{\x03\x83\xe9\ +X\xd6\x13\x13c%\xb3\xb6\x06\x10\xed\x00\xa4R\x5c\x00\ +\x09\x00\x09A\xc0`O\xb96\xc08\xdc\xf9\xa8\xd8\xb6\ +}]\xa9Tn\xe0\x1aZ7\x80\x92I\xcb4M5\ +\xb3\xb5\xb5\x9dl\xab\x02\xd0^.*\x00\xb86@\x10\ +\x08\x0ba\x998\x08_C\xf6\xb6l\x0f\xff\xee\xc0@\ +\x04Y\xd6\xac\xa9i\xfa{\x18\xcc\x85v\x00d\xf6\x98\ +\x80\xf1\xcc\xe1Z(\xd72\xaf\xf0\x98\x1c\xccf\x88\xd9\ +\xd9\x19\xd3\xe7\xd3\xb3\xf9\xfc\xe1|\xcb\x00\x81@\x00S\ +\xaarA\x84\xab\xc6\xa4C\xcc\xa9e\xcd\xa4\xe8\xdf \ +\x22\x91\x10?\xac\x00\x82f\xf7\xf6\x00\xa2\xf5\x0a\x10\xb1\ +rA\xeeP\x09\xbe\x8a\x16@A\x98\x14\xbc\x0d\x22\x1c\ +\xe6\xcf\x8e1\xbfa\xe8\xd9b\xf1\xcb\xd3\x96\x00\xa0\x02\ +|\x91\x102{\xe1r0\xef\x02\x11\x0a\x89?5~\ +J\xc9\xf6\xe9\xe9\x99u'\x80\x8b\x8b\x0b,*P7\ +W\x5c\x0ef+\x10\xc1`\x00\x8d\x8e\x8e\x00\x84\x9a;\ +;\xfbf\xdd\xa9\x02\x84\xd0\xe6\x90+\xfco\x10}h\ +d\xe4\x91_U\x95\xdc\xf9\xf9\x8f9O\xc5\x9b\x8eb\ +\xe8\xb7\xf6\xab\x5c\xfe\xeeW>\xfejdd$\x19\x18\x18\ +\x80\x17\x86\xc6\x02\x7f\xd4}\xe5\x84\xc7\xe9~r\xf8L\ +?i\x802\x99UUU$..N\xde\xfa\x0b\xf0\ +Gu\xd7\x12\x1a\xfa\x08\xfb\xe6\xd7b\xc7\xdb\xdf\x92m\ +\xa0\x1az\x04%\x07\xef\xf7\x82\x82\x02\xf9\xc1\xf3\x8c*\ +P\x8a\xb7 @\x9d\xcc9\x1d\x1d\x8d\xbb\xd9\x22\xce\ +\xee\x98\x00\xf5Vv \xd6\xf0Ffffdww\ +7#k\xbd\x95F\x82R\x95]\xf6G\xaan\xfe\xd9\ +\x0e\xaa\xea\xc6\x22\x14\x0a)))!\xe9\xe9\xe9\xf2\x83\ +\xb7\x04\xa5J[\xc6\xf0\xf2\xb5\x85\xe4\xf2\xeb\x0b7A\ +\x9d\xf8l\x0eJm\xdf\xbe\xfd\xcb\xea\xeaj\xb7J\xa5\ +\x92\xef\xbd\x19JX>\x19\xc1\xd1K\x93\xea#m\x13\ +\xbf\x80:vy\x0aJXU*P\x99\xd5V\xab\xe7\ +\xbe\x97\xaf~\x18\xfe8\xd42\xd6_\xda6\x11U\xda\ +:\x06\x7fT\xc6\xc4,\x1f-,\xf4\x14$\xb2<\x0c\ +\x1fT\xf0r\xa0\xe9\x07ht\xfa,^\x10\x86\xaf\x94\ +=4\x07?\x94\xb3\xac5G\xa7\xd3%\xcd\xcc@m\ +0\xe0\xfc\xfc\x83\x83\x83\ +\xe3\xb5\xa2\xd8\x0a\x0f?; \x09\x1c\xa7\x85B\x06\x83\ +\xe1u5\xcb\x92\x17\x87\x86t\xfbGF\x9c,\xcf\xaf\ +\xdc\x9b\x9cd\x86\xef\xde-ldY\xf8m\xd7K\x1d\ +=I\xc7\xdb\xcd;\x0e7C\x01&77\x97\x18\x8d\ +\xc6\xfb\x1e6)*U\x1bd\x94w\x80\xe7z\x04\xce\ +\xf9\xcch\xeb\x11(PNo==\xfd\xa1\xc3\xe1\x98\x92$\xe9I\x00\ +\xd6\x0dM\xc0d21\xf0\x8c\xfb\xf2\x98\x99K\xaf\x22\ +\x83\xf9~\xd8\xf1s\x83\x8a\xe3%\xb7\x9d\x13\xe7\xb6d\ +\xd5v\x0ab\xf0\x81\xd0\x9c\xba P\x8d'k\xa25\ +\x1a\xcd\x14\xfd\xdd\xb6\xc4\xc4\xc4El\x84\xe7\xaf\x04*\ +//\xef\xfeq\xef\xdf\xdf?\x9b\xb7\x9b\xe0\xd1w\x1b\ +\x9e\xdf\xf7\x14\xc1\xe3u\x04\xe9V\xdb\xf1S\x1f_\xc5\ +\xbf\xc9\xd3\x01\x9f\xa3\x0f\x17Z/\xe3\x7f\xe1/\x17\x85\ +\xd6\x06q(\x0e\x10\x00\x00\x00\x00IEND\xaeB\ +`\x82\ \x00\x00\x02V\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -1210,6 +1429,113 @@ G%\xc7A \x00\x1d\xd0\x80I\xe0\x03\x10;3\x85\ \xfaS\x08V\x01()\xc7\xe4\xb9C\x95,\x01\xd77\ \x9aw\xed\x7f\xefoJ\x88l\x9a\x02\xc2\xbb\x00\x00\x00\ \x00\x00IEND\xaeB`\x82\ +\x00\x00\x06\x8f\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\ +\x00\x00\x00\x09pHYs\x00\x00\x03v\x00\x00\x03v\ +\x01}\xd5\x82\xcc\x00\x00\x00\x19tEXtSof\ +tware\x00www.inksca\ +pe.org\x9b\xee<\x1a\x00\x00\x06\x0cID\ +ATx\xda\xddWYLUW\x14=NiSQ\ +\x8b\xad\xb1\xad\x16\x8d\x1dR\xd39\xa6\xa6\x95\xb6Im\ +b\xda\xaf\xfe\xe0w\xd3~\x01%6V\x1cA\x8b\x8a\ +\x10)NLB\xa1\x10@\x85\x08\x05\xc2P\xa8\x81\xfa\ +\xe1\x00\xca\xa48\x81\xa2(\x93\x82\x82\xcc\xd3\xe3\x9d\xdd\ +\xb5N^o.\x06\x1b\xb0$&}\xc9\x0a\xbcs\xef\ +;{\xed\xbd\xd7\xdeg\x1f%\x22O\x15\xff/\x02\xf8\ +L\x0b\x0a\x0ar{*\x046n\xdc\xf8Ahhh\ +[zz\xfahHHH*\x88\xcc|\xf4\x9d\x83\x07\ +\x0f.\xf2\xf6\xf6\x0e^\xb5j\xd5\xb7nnn\xeeS\ +F`\xd3\xa6M\xcb\xf7\xed\xdb\xd7WYY)W\xaf\ +^\x95K\x97.i\x18\xabpEczuu\xf5G\ +\x87\x0e\x1d\xfa\x04k\xad>>>G===W\xcc\ +\x993gj\x08l\xd9\xb2\xe5\xf5\xb0\xb0\xb0\xee\x0b\x17\ +.\xc8\xe5\xcb\x97\xa5\xa6\xa6Fjkk\xe5\xc6\x8d\x1b\ +:>>\xbe\xbd\xb4\xb4\xb4\x0c\xebCg\xce\x9c\x19\x01\ +\x89R___\xf7)K\xc1\x86\x0d\x1b\x96\xec\xdd\xbb\ +\xb7\x83F\xeb\xea\xea\xe4\xc1\x83\x07RUU%\xf0X\ +\xea\xeb\xeb\xe5\xf6\xed\xdb\x92\x96\x96\xa6\xcf\x9f?/\xd7\ +\xaf_\x97k\xd7\xae\x05N\x95\x06\x18\xf6W\x90\xf3v\ +\x84[n\xde\xbci\x0c\xb6\xb6\xb6Jww\xb70\x1a\ +$u\xeb\xd6-\xae\x19\x12\x88Joss\xf3\xe2)\ +!\xb0u\xeb\xd6\x05{\xf6\xeci\xb9r\xe5\x8a\xdc\xb9\ +s\x87\xde\x1b\x83\x0d\x0d\x0d\xd2\xde\xden\x91\xf8\xe7y\ +cc\xa3NHH\xe8\x1cO\x98O\x92s\xf7\xdd\xbb\ +w7 \x9c\x1a\x1e\x19\x0f\x07\x07\x07\x19^\x8a\x8f\x06\ +\x99\x0aC\xe2\xe2\xc5\x8bF\x0fMMM\xd4\x84\x13\xa4\ +S\xff\x13\x01z\xb0k\xd7\xaeZ(]\xdf\xbd{\xd7\ +\x0aqGG\x07I\xd0\x98\xf1\x9a\xc4\x1e>|H\x12\ +\x8c\x0c\xf3\xcf\xf7\x18\x95\xd1\x80\x80\x80\x1f\x9e\x98\xc0\xe6\ +\xcd\x9b\xbf\xce\xcd\xcd\x1d\xbe\x7f\xff\xbe\xf4\xf5\xf51\xb4\ +F\xf9mmm4h\x91\x00,=\xf4\xf4\xf4Xz\ +\xe0zjj\xea\xc0\xda\xb5kgL\x86\x00=\x9f\xbe\ +m\xdb\xb6H\xd4\xf1pdd\xa4\x93\xb5\xce\xcd\x1d\x0e\ +\x87\x09/\xbf\x83\x14\xd7H\x82\x9a`\xc8I\x8cD\xcd\ +:{\xc4\xe9\xd3\xa7%11q\x88\xfbM\x98\x00\xdb\ +\xeb\xf6\xed\xdb\xd3\xa1r\xa7\xe0\x93\x94\x94$qqq\ +\x9a\xf9\xee\xed\xed\xb5H\xd0\xbb\xce\xceN\xb3644\ +\xc4\xb0\xd3k\x920d\xd0\x07$##\xc3\x89\xea\xf9\ +~R)\x80\xe7\xbf\xc1\xc3Q|\xe4\xde\xbd{\xc6\xa3\ +\xa8\xa8(\x1d\x1b\x1b\xabY\xef\x03\x03\x03\x16\x09\x1a\xea\ +\xea\xea\x92\xfe\xfe~\x92\xa00\x99\x22\xe3yff\xa6\ +\x13)\xfciR\x22\x84`\x22(\x1cnF#$A\ +\xcf\xe8exx\xb8\x8e\x89\x89\xd1\x0c-\xc3\xceg\x14\ +\x1f\xbd\xe6s\x86\x9d\xbd\xe1\xd4\xa9S\x92\x95\x95\xa5Q\ +\xba?O\xea0\xc2\x0fB\xce\x9d;\xe7\xa0\xc7\x14\x12\ +=\xa5\x91\x91\x91\x11\xe6\xd8D\x03\x15\xa1\xa1\x09]V\ +V\xc6u\x8b\x04\x1b\x13SB\xcf\xb3\xb3\xb3u``\ +`\xd8dNC\xd6z\x00\x98;l\xa2b.\xe9\x19\ +\x8dX\xe1\xa5!DI\xa3\xc7\xeb\xb3g\xcf2J$\ +\xcbr3\x9e\xe7\xe4\xe4\xe8\x1d;v\x1c\xb6\x8c\xc5\xa9\ +Y*Je\x02_>\x8e\x00\x8f\xd5\x1fKJJ\x1c\ +\x14\x14@\xcf\xad\xf2\xa2\xd74@\x12\x5c\xa7\xfaYb\ +\xf8\x8d\xde\xbf\x7f\xbf.**\x221\xcb8\xc4{\xc4\ +2t\x5c\xcdP\xb1*\x03\x10\xa0O\x1dV\x9e\x5c\x7f\ +\xb4\xbf\x7fWXX8\xc2\x92b[%\xd8\xd5h\x8c\ +\xc2\xa2A6 \x0a\x8d$\x18\x11V\x03N\xa1\x8b\x09gt\xce\xea\x9c\xd99\xbbs\x86\xe7,\ +\xcf\x99\x9e\xb3=\xaa\xa3\x9c$0RIrr\xb2D\ +DD\x0c\xf2.`\xdf\xc84\x9b\x22\x95\xa4\xfeT\x02\ +\x0c\xa9\x13j\xcd\x84oF\xbc\xa5\xf0\xb6\xc2[\x0bo\ +/\xe3\x09\x13\x06S\x00'\xdak'oA\xe3n\x16\ +\xa4\xa6\xab\x12\x95\xaa\xfeR\xdf<\xd1\xd5\x0c\x9f\x99\xc0\ +s\xc0<\xe0E\xe0e\xc0\x03X\x06\xbc\xe9\xe1\xe1\xb1\ +\x02\x7f\xdf\x01\xde\x05\xde\xb3\x81\xdf\xdf\x06\x96\xf3=\xe0\ +5`)\xf0*\xf0\x12\xb0\x00x\x1ep\x03\x9e\x01\xc6\ +\x8ed\xec\xd9\x5c\x04\x9e\x05\xe6\x02/\xb8\x8c/\x01\xde\ +pm\xfe!\xf01\xf0\x19\xb0\x1aX\x03|\xe5\xfa\xfb\ +\x05\xf0)\xb0\x92\xef\xf1}\x12q\x91X\x04,\x04\xe6\ +so\x97\x8dY\x80i\xd5\x7f\x03\x81\xe3\xecT\x9c\xdf\ +M_\x00\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x06\xf7\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -1739,6 +2065,76 @@ K\x80@\x89\x15\x8d\xc04\xd5\xb5^\xaf\x1bx\xfa\x19\ \x84\xe7\x04\xcf\x88\xfd\xfd\xfd\xe4\xe8\xe8\xc8\x9dL&\x14\ \xc7\xcc\x7f5p\xf2g\x94\xf7\x1f\xdf\x9a\xd2\x93\xfbC\ \xb7\xa7\x00\x00\x00\x00IEND\xaeB`\x82\ +\x00\x00\x04<\ +\x89\ +PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ +\x00\x00 \x00\x00\x00 \x08\x06\x00\x00\x00szz\xf4\ +\x00\x00\x00\x01sRGB\x00\xae\xce\x1c\xe9\x00\x00\x00\ +\x06bKGD\x00\xff\x00\xff\x00\xff\xa0\xbd\xa7\x93\x00\ +\x00\x00\x09pHYs\x00\x00\x0d\xd7\x00\x00\x0d\xd7\x01\ +B(\x9bx\x00\x00\x00\x07tIME\x07\xd9\x06\x0a\ +\x00\x09%\x83\xde\x9d\x8d\x00\x00\x03\xbcIDATx\ +\xda\xedV\xcdKTQ\x14\xbfw\xe6\xcdG\xcf)\xc6\ +\x19B\xc5\x8a\x1aE\x86\xa4\x85\x91!\x13\x99\x8b(\x0d\ +\x94\xc12\x93\x04\xc9\x16m\x82P\xe8\x0f\x88v-l\ +\x1bA\xad\x22RC\xcbA\xa6,\xa5\x19\xd0\x81\xc6>\ +\x16-\xc2\x92 \x0cc2\xc7\xf2c\x9c\xcf\xdb9\xd1\ +y\xbc\xde\xbc)\xc6 \x10\xe6\x07\x87{\xdf\xbc;\xe7\ +\xf7;\xe7\xdc{\xeec\x05\x14\xb0\xa9\x10\x0e\xbf\xfa\xe7\ +5Z\xf0<\xc8w\xc0\xd0$\x84h\xe0\x9c\xef\x87\xb9\ +\x13l;\x98\x00\xfb\x02\xf6\x15\xdeM\xc3\xbbg0\xf7\ +\xd7\xd6\xd6\xccOM=g\x1e\xcf\xc1\x8d\x09\x08\x04&\ +\xd9\x91#\x87X(4}.\x93I\xf5\x18\x8d\xd2\xbe\ +m\xdb\xb62Y\xb6\x0a\xab\xd5\xcc\x8dF#\x032\x06\ +\xa4,\x9dN\xb3D\x22\xc5\xd6\xd7\xe3\x02\x8c\xc7bk\ +,\x99\xcc\xbc2\x18\x0c}\x1eO\xed\x1d\xf2\x95\x97\x80\ +`p\xca\x93J\xa5\xee\xdb\xed\xf6\xb2\xd2\xd2\xed\xc2f\ ++\xe2\xf0\x8c\x84\x8a!p\xccd28*s\x14\x86\ +b\xbe\x7f_\xe6\xd1\xe8\xb7\x8f\x92$\x9d\xac\xaf\xf7L\ +\xeb\xf1\x18\xd4\x0f~\xffS\x86\x98\x98\x08^\x81\xa8&\ +\xab\xab\xdd\xa5nw%+*\x9299V\x1b\x01\xe7\ +@\xc2,\x16\x0b\xb3\xd9l\xb0\xbe\x889\x9d\x0e\xeer\ +\xedfUU\x15;\xc1Wx|?\xff\x19\xdb\xf0;I2\xf7\ +\xb5\xb4\x9c\xb8A\xbe6\xfaIF7\xa5[\x88\xccq\ +\xa0k\x00\xc2\x1a\xfc\x1c\x83h\xe5_%Y\xc1\xa0a\ +|\x01\x85\x09\x800\x7fss\xd3{\xf6\x7fABG\ +Y\x01\x05l*\xfc\x00!\x00\x12\xf1%U\xb6\x0e\x00\ +\x00\x00\x00IEND\xaeB`\x82\ \x00\x00\x02\x92\ \x89\ PNG\x0d\x0a\x1a\x0a\x00\x00\x00\x0dIHDR\x00\ @@ -1875,6 +2271,10 @@ qt_resource_name = b"\ \x00z\ \x00o\x00o\x00m\x00-\x00o\x00r\x00i\x00g\x00i\x00n\x00a\x00l\x00.\x00p\x00n\x00g\ \ +\x00\x0f\ +\x0bb\xb8g\ +\x00d\ +\x00r\x00a\x00w\x00-\x00c\x00i\x00r\x00c\x00l\x00e\x00.\x00p\x00n\x00g\ \x00\x14\ \x0b\xa9\xab'\ \x00d\ @@ -1889,6 +2289,15 @@ qt_resource_name = b"\ \x09\xd0z\x07\ \x00a\ \x00r\x00r\x00o\x00w\x00-\x00u\x00p\x00.\x00p\x00n\x00g\ +\x00\x11\ +\x06\xfb\x85G\ +\x00d\ +\x00r\x00a\x00w\x00-\x00t\x00r\x00i\x00a\x00n\x00g\x00l\x00e\x00.\x00p\x00n\x00g\ +\ +\x00\x0d\ +\x0f\xba\x1e'\ +\x00d\ +\x00r\x00a\x00w\x00-\x00p\x00a\x00t\x00h\x00.\x00p\x00n\x00g\ \x00\x0d\ \x0b\xe6\x1f\xa7\ \x00d\ @@ -1922,6 +2331,11 @@ qt_resource_name = b"\ \x00d\ \x00r\x00a\x00w\x00-\x00b\x00e\x00z\x00i\x00e\x00r\x00-\x00c\x00u\x00r\x00v\x00e\ \x00s\x00.\x00p\x00n\x00g\ +\x00\x13\ +\x04\xc4\x04G\ +\x00n\ +\x00e\x00t\x00w\x00o\x00r\x00k\x00-\x00c\x00o\x00n\x00n\x00e\x00c\x00t\x00.\x00p\ +\x00n\x00g\ \x00\x0c\ \x06\xeb\x97\xe7\ \x00z\ @@ -1948,6 +2362,10 @@ qt_resource_name = b"\ \x00d\ \x00o\x00c\x00u\x00m\x00e\x00n\x00t\x00-\x00s\x00a\x00v\x00e\x00.\x00p\x00n\x00g\ \ +\x00\x10\ +\x03\xe6\xd3g\ +\x00d\ +\x00r\x00a\x00w\x00-\x00e\x00l\x00l\x00i\x00p\x00s\x00e\x00.\x00p\x00n\x00g\ \x00\x12\ \x09\xb3>\xc7\ \x00d\ @@ -1965,49 +2383,59 @@ qt_resource_struct = b"\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x15\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x1a\x00\x00\x00\x03\ \x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x01r\x00\x00\x00\x00\x00\x01\x00\x00:\x16\ +\x00\x00\x01\xde\x00\x00\x00\x00\x00\x01\x00\x00G\x5c\ \x00\x00\x01\x9f{C\xf1'\ -\x00\x00\x02\x02\x00\x00\x00\x00\x00\x01\x00\x00Pr\ +\x00\x00\x02\x9a\x00\x00\x00\x00\x00\x01\x00\x00dK\ \x00\x00\x01\x9f{0\xc99\ -\x00\x00\x018\x00\x00\x00\x00\x00\x01\x00\x00/`\ +\x00\x00\x01\xa4\x00\x00\x00\x00\x00\x01\x00\x00<\xa6\ \x00\x00\x01\x9f\x7f&\x83\xcd\ -\x00\x00\x01\x18\x00\x00\x00\x00\x00\x01\x00\x00'x\ +\x00\x00\x01\x84\x00\x00\x00\x00\x00\x01\x00\x004\xbe\ \x00\x00\x01\x9f{C\xf1\x18\ -\x00\x00\x02p\x00\x00\x00\x00\x00\x01\x00\x00`\xe1\ +\x00\x00\x03R\x00\x00\x00\x00\x00\x01\x00\x00}\x9f\ +\x00\x00\x01\x9f\x7fY\xceg\ +\x00\x00\x02P\x00\x00\x00\x00\x00\x01\x00\x00V\xbd\ +\x00\x00\x01\x9f\x7fV\xd5\xc0\ +\x00\x00\x03\x08\x00\x00\x00\x00\x00\x01\x00\x00t\xba\ \x00\x00\x01\x9f\x7f&\x83r\ -\x00\x00\x01\xe4\x00\x00\x00\x00\x00\x01\x00\x00Iw\ +\x00\x00\x02|\x00\x00\x00\x00\x00\x01\x00\x00]P\ \x00\x00\x01\x9f\x7f&\x83\xb1\ -\x00\x00\x01T\x00\x00\x00\x00\x00\x01\x00\x006\x96\ +\x00\x00\x00\xfc\x00\x00\x00\x00\x00\x01\x00\x00$|\ +\x00\x00\x01\x9f\x7fY\xce\x82\ +\x00\x00\x01\xc0\x00\x00\x00\x00\x00\x01\x00\x00C\xdc\ \x00\x00\x01\x9f{C\xf1.\ -\x00\x00\x00\xf8\x00\x00\x00\x00\x00\x01\x00\x00!\xca\ +\x00\x00\x01d\x00\x00\x00\x00\x00\x01\x00\x00/\x10\ \x00\x00\x01\x9f{{\xa5\xd5\ -\x00\x00\x02\xba\x00\x00\x00\x00\x00\x01\x00\x00i\xc6\ +\x00\x00\x03x\x00\x00\x00\x00\x00\x01\x00\x00\x81\xdf\ \x00\x00\x01\x9f\x7f&\x83\x10\ -\x00\x00\x00\xba\x00\x00\x00\x00\x00\x01\x00\x00\x1b\xcd\ +\x00\x00\x00\xde\x00\x00\x00\x00\x00\x01\x00\x00 \xd9\ \x00\x00\x01\x9f\x7f&\x83~\ -\x00\x00\x02L\x00\x00\x00\x00\x00\x01\x00\x00\x5c\xfe\ +\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x00p\xd7\ \x00\x00\x01\x9f\x7f&\x83T\ \x00\x00\x00^\x00\x00\x00\x00\x00\x01\x00\x00\x0c\xc1\ +\x00\x00\x01\x9f\x7fY\xce^\ +\x00\x00\x00\x82\x00\x00\x00\x00\x00\x01\x00\x00\x11\xcd\ \x00\x00\x01\x9f{0\xc9B\ -\x00\x00\x00\xd8\x00\x00\x00\x00\x00\x01\x00\x00\x1fp\ +\x00\x00\x01D\x00\x00\x00\x00\x00\x01\x00\x00,\xb6\ \x00\x00\x01\x9f\x7f&\x83)\ -\x00\x00\x02*\x00\x00\x00\x00\x00\x01\x00\x00W|\ +\x00\x00\x02\xc2\x00\x00\x00\x00\x00\x01\x00\x00kU\ \x00\x00\x01\x9f{C\xf1N\ -\x00\x00\x01\xb2\x00\x00\x00\x00\x00\x01\x00\x00EH\ +\x00\x00\x02\x1e\x00\x00\x00\x00\x00\x01\x00\x00R\x8e\ \x00\x00\x01\x9f\x7f&\x82\xf2\ -\x00\x00\x00\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x15-\ +\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x1a9\ \x00\x00\x01\x9f{\x8d\xf34\ \x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ \x00\x00\x01\x9f{0\xc9+\ -\x00\x00\x01\x92\x00\x00\x00\x00\x00\x01\x00\x00=v\ +\x00\x00\x01\xfe\x00\x00\x00\x00\x00\x01\x00\x00J\xbc\ \x00\x00\x01\x9f{C\xf1=\ \x00\x00\x006\x00\x00\x00\x00\x00\x01\x00\x00\x05\x86\ \x00\x00\x01\x9f\x7f&\x83\x99\ -\x00\x00\x02\xe4\x00\x00\x00\x00\x00\x01\x00\x00l\x5c\ +\x00\x00\x03\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x84u\ \x00\x00\x01\x9f{{\xa5\xe3\ -\x00\x00\x02\x92\x00\x00\x00\x00\x00\x01\x00\x00d\xd3\ +\x00\x00\x01$\x00\x00\x00\x00\x00\x01\x00\x00'\xef\ +\x00\x00\x01\x9f\x7fV\xd5\xe5\ +\x00\x00\x03*\x00\x00\x00\x00\x00\x01\x00\x00x\xac\ \x00\x00\x01\x9f{0\xc9R\ " diff --git a/BEdit/src/bedit/gui/generated/ui_connection_chooser_dialog.py b/BEdit/src/bedit/gui/generated/ui_connection_chooser_dialog.py new file mode 100644 index 0000000..7723848 --- /dev/null +++ b/BEdit/src/bedit/gui/generated/ui_connection_chooser_dialog.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file 'connection_chooser_dialog.ui' +## +## Created by: Qt User Interface Compiler version 6.11.1 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogButtonBox, + QLabel, QListWidget, QListWidgetItem, QSizePolicy, + QVBoxLayout, QWidget) + +class Ui_ConnectionChooserDialog(object): + def setupUi(self, ConnectionChooserDialog): + if not ConnectionChooserDialog.objectName(): + ConnectionChooserDialog.setObjectName(u"ConnectionChooserDialog") + ConnectionChooserDialog.resize(460, 280) + self.dialogLayout = QVBoxLayout(ConnectionChooserDialog) + self.dialogLayout.setObjectName(u"dialogLayout") + self.promptLabel = QLabel(ConnectionChooserDialog) + self.promptLabel.setObjectName(u"promptLabel") + + self.dialogLayout.addWidget(self.promptLabel) + + self.connectionList = QListWidget(ConnectionChooserDialog) + self.connectionList.setObjectName(u"connectionList") + self.connectionList.setAlternatingRowColors(True) + + self.dialogLayout.addWidget(self.connectionList) + + self.buttonBox = QDialogButtonBox(ConnectionChooserDialog) + self.buttonBox.setObjectName(u"buttonBox") + self.buttonBox.setStandardButtons(QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.Ok) + + self.dialogLayout.addWidget(self.buttonBox) + + + self.retranslateUi(ConnectionChooserDialog) + self.buttonBox.accepted.connect(ConnectionChooserDialog.accept) + self.buttonBox.rejected.connect(ConnectionChooserDialog.reject) + self.connectionList.itemDoubleClicked.connect(ConnectionChooserDialog.accept) + + QMetaObject.connectSlotsByName(ConnectionChooserDialog) + # setupUi + + def retranslateUi(self, ConnectionChooserDialog): + ConnectionChooserDialog.setWindowTitle(QCoreApplication.translate("ConnectionChooserDialog", u"Select a Connection", None)) + self.promptLabel.setText(QCoreApplication.translate("ConnectionChooserDialog", u"Select a connection:", None)) + # retranslateUi + diff --git a/BEdit/src/bedit/gui/generated/ui_icon_editor_dialog.py b/BEdit/src/bedit/gui/generated/ui_icon_editor_dialog.py index 83f44d7..8e99556 100644 --- a/BEdit/src/bedit/gui/generated/ui_icon_editor_dialog.py +++ b/BEdit/src/bedit/gui/generated/ui_icon_editor_dialog.py @@ -21,6 +21,7 @@ from PySide6.QtWidgets import (QAbstractButton, QApplication, QDialog, QDialogBu QWidget) from bedit.gui.graphics.icon_canvas import IconCanvasView +from . import resources_rc class Ui_IconEditorDialog(object): def setupUi(self, IconEditorDialog): @@ -33,6 +34,9 @@ class Ui_IconEditorDialog(object): self.shapeToolbarLayout.setObjectName(u"shapeToolbarLayout") self.pointerButton = QToolButton(IconEditorDialog) self.pointerButton.setObjectName(u"pointerButton") + icon = QIcon() + icon.addFile(u":/icons/icons/edit-select.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.pointerButton.setIcon(icon) self.pointerButton.setCheckable(True) self.pointerButton.setChecked(True) @@ -45,36 +49,54 @@ class Ui_IconEditorDialog(object): self.addRectangleButton = QToolButton(IconEditorDialog) self.addRectangleButton.setObjectName(u"addRectangleButton") + icon1 = QIcon() + icon1.addFile(u":/icons/icons/draw-rectangle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.addRectangleButton.setIcon(icon1) self.addRectangleButton.setCheckable(True) self.shapeToolbarLayout.addWidget(self.addRectangleButton) self.addCircleButton = QToolButton(IconEditorDialog) self.addCircleButton.setObjectName(u"addCircleButton") + icon2 = QIcon() + icon2.addFile(u":/icons/icons/draw-circle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.addCircleButton.setIcon(icon2) self.addCircleButton.setCheckable(True) self.shapeToolbarLayout.addWidget(self.addCircleButton) self.addEllipseButton = QToolButton(IconEditorDialog) self.addEllipseButton.setObjectName(u"addEllipseButton") + icon3 = QIcon() + icon3.addFile(u":/icons/icons/draw-ellipse.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.addEllipseButton.setIcon(icon3) self.addEllipseButton.setCheckable(True) self.shapeToolbarLayout.addWidget(self.addEllipseButton) self.addLineButton = QToolButton(IconEditorDialog) self.addLineButton.setObjectName(u"addLineButton") + icon4 = QIcon() + icon4.addFile(u":/icons/icons/draw-bezier-curves.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.addLineButton.setIcon(icon4) self.addLineButton.setCheckable(True) self.shapeToolbarLayout.addWidget(self.addLineButton) self.addTriangleButton = QToolButton(IconEditorDialog) self.addTriangleButton.setObjectName(u"addTriangleButton") + icon5 = QIcon() + icon5.addFile(u":/icons/icons/draw-triangle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.addTriangleButton.setIcon(icon5) self.addTriangleButton.setCheckable(True) self.shapeToolbarLayout.addWidget(self.addTriangleButton) self.addTextButton = QToolButton(IconEditorDialog) self.addTextButton.setObjectName(u"addTextButton") + icon6 = QIcon() + icon6.addFile(u":/icons/icons/draw-text.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.addTextButton.setIcon(icon6) self.addTextButton.setCheckable(True) self.shapeToolbarLayout.addWidget(self.addTextButton) @@ -85,16 +107,25 @@ class Ui_IconEditorDialog(object): self.zoomInButton = QToolButton(IconEditorDialog) self.zoomInButton.setObjectName(u"zoomInButton") + icon7 = QIcon() + icon7.addFile(u":/icons/icons/zoom-in.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.zoomInButton.setIcon(icon7) self.shapeToolbarLayout.addWidget(self.zoomInButton) self.zoomOutButton = QToolButton(IconEditorDialog) self.zoomOutButton.setObjectName(u"zoomOutButton") + icon8 = QIcon() + icon8.addFile(u":/icons/icons/zoom-out.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.zoomOutButton.setIcon(icon8) self.shapeToolbarLayout.addWidget(self.zoomOutButton) self.centerButton = QToolButton(IconEditorDialog) self.centerButton.setObjectName(u"centerButton") + icon9 = QIcon() + icon9.addFile(u":/icons/icons/zoom-original.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.centerButton.setIcon(icon9) self.shapeToolbarLayout.addWidget(self.centerButton) @@ -142,18 +173,18 @@ class Ui_IconEditorDialog(object): self.addLineButton.setText(QCoreApplication.translate("IconEditorDialog", u"Line", None)) self.addTriangleButton.setText(QCoreApplication.translate("IconEditorDialog", u"Triangle", None)) self.addTextButton.setText(QCoreApplication.translate("IconEditorDialog", u"Text", None)) - self.zoomInButton.setText(QCoreApplication.translate("IconEditorDialog", u"+", None)) #if QT_CONFIG(tooltip) self.zoomInButton.setToolTip(QCoreApplication.translate("IconEditorDialog", u"Zoom in", None)) #endif // QT_CONFIG(tooltip) - self.zoomOutButton.setText(QCoreApplication.translate("IconEditorDialog", u"\u2212", None)) + self.zoomInButton.setText(QCoreApplication.translate("IconEditorDialog", u"+", None)) #if QT_CONFIG(tooltip) self.zoomOutButton.setToolTip(QCoreApplication.translate("IconEditorDialog", u"Zoom out", None)) #endif // QT_CONFIG(tooltip) - self.centerButton.setText(QCoreApplication.translate("IconEditorDialog", u"Fit", None)) + self.zoomOutButton.setText(QCoreApplication.translate("IconEditorDialog", u"\u2212", None)) #if QT_CONFIG(tooltip) self.centerButton.setToolTip(QCoreApplication.translate("IconEditorDialog", u"Fit and center the icon canvas", None)) #endif // QT_CONFIG(tooltip) + self.centerButton.setText(QCoreApplication.translate("IconEditorDialog", u"Fit", None)) self.deleteSelectedButton.setText(QCoreApplication.translate("IconEditorDialog", u"Delete selected", None)) self.portHintLabel.setText(QCoreApplication.translate("IconEditorDialog", u"Green points are inputs; red points are outputs. Drag them to place connection anchors.", None)) # retranslateUi diff --git a/BEdit/src/bedit/gui/generated/ui_main_window.py b/BEdit/src/bedit/gui/generated/ui_main_window.py index 59553a7..10c11df 100644 --- a/BEdit/src/bedit/gui/generated/ui_main_window.py +++ b/BEdit/src/bedit/gui/generated/ui_main_window.py @@ -235,33 +235,36 @@ class Ui_MainWindow(object): self.connectToolButton = QToolButton(self.workspaceHeader) self.connectToolButton.setObjectName(u"connectToolButton") + icon16 = QIcon() + icon16.addFile(u":/icons/icons/network-connect.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.connectToolButton.setIcon(icon16) self.connectToolButton.setCheckable(True) self.workspaceHeaderLayout.addWidget(self.connectToolButton) self.boxToolButton = QToolButton(self.workspaceHeader) self.boxToolButton.setObjectName(u"boxToolButton") - icon16 = QIcon() - icon16.addFile(u":/icons/icons/draw-rectangle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) - self.boxToolButton.setIcon(icon16) + icon17 = QIcon() + icon17.addFile(u":/icons/icons/draw-rectangle.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.boxToolButton.setIcon(icon17) self.boxToolButton.setCheckable(True) self.workspaceHeaderLayout.addWidget(self.boxToolButton) self.lineToolButton = QToolButton(self.workspaceHeader) self.lineToolButton.setObjectName(u"lineToolButton") - icon17 = QIcon() - icon17.addFile(u":/icons/icons/draw-bezier-curves.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) - self.lineToolButton.setIcon(icon17) + icon18 = QIcon() + icon18.addFile(u":/icons/icons/draw-bezier-curves.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.lineToolButton.setIcon(icon18) self.lineToolButton.setCheckable(True) self.workspaceHeaderLayout.addWidget(self.lineToolButton) self.textToolButton = QToolButton(self.workspaceHeader) self.textToolButton.setObjectName(u"textToolButton") - icon18 = QIcon() - icon18.addFile(u":/icons/icons/draw-text.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) - self.textToolButton.setIcon(icon18) + icon19 = QIcon() + icon19.addFile(u":/icons/icons/draw-text.png", QSize(), QIcon.Mode.Normal, QIcon.State.Off) + self.textToolButton.setIcon(icon19) self.textToolButton.setCheckable(True) self.workspaceHeaderLayout.addWidget(self.textToolButton) @@ -272,30 +275,6 @@ class Ui_MainWindow(object): self.workspaceHeaderLayout.addWidget(self.rotateToolButton) - self.routingLabel = QLabel(self.workspaceHeader) - self.routingLabel.setObjectName(u"routingLabel") - - self.workspaceHeaderLayout.addWidget(self.routingLabel) - - self.directRoutingButton = QToolButton(self.workspaceHeader) - self.directRoutingButton.setObjectName(u"directRoutingButton") - self.directRoutingButton.setCheckable(True) - - self.workspaceHeaderLayout.addWidget(self.directRoutingButton) - - self.angledRoutingButton = QToolButton(self.workspaceHeader) - self.angledRoutingButton.setObjectName(u"angledRoutingButton") - self.angledRoutingButton.setCheckable(True) - self.angledRoutingButton.setChecked(True) - - self.workspaceHeaderLayout.addWidget(self.angledRoutingButton) - - self.splineRoutingButton = QToolButton(self.workspaceHeader) - self.splineRoutingButton.setObjectName(u"splineRoutingButton") - self.splineRoutingButton.setCheckable(True) - - self.workspaceHeaderLayout.addWidget(self.splineRoutingButton) - self.workspaceEditorLayout.addWidget(self.workspaceHeader) @@ -545,10 +524,6 @@ class Ui_MainWindow(object): self.rotateToolButton.setToolTip(QCoreApplication.translate("MainWindow", u"Rotate selected blocks clockwise", None)) #endif // QT_CONFIG(tooltip) self.rotateToolButton.setText(QCoreApplication.translate("MainWindow", u"Rotate", None)) - self.routingLabel.setText(QCoreApplication.translate("MainWindow", u"Line:", None)) - self.directRoutingButton.setText(QCoreApplication.translate("MainWindow", u"Direct", None)) - self.angledRoutingButton.setText(QCoreApplication.translate("MainWindow", u"Angled", None)) - self.splineRoutingButton.setText(QCoreApplication.translate("MainWindow", u"Spline", None)) self.jsonEditor.setPlaceholderText(QCoreApplication.translate("MainWindow", u"Component JSON", None)) self.emptyWorkspaceLabel.setText(QCoreApplication.translate("MainWindow", u"No document open", None)) self.menuFile.setTitle(QCoreApplication.translate("MainWindow", u"&File", None)) diff --git a/BEdit/src/bedit/gui/graphics/workspace.py b/BEdit/src/bedit/gui/graphics/workspace.py index 5fede0f..a9e40bf 100644 --- a/BEdit/src/bedit/gui/graphics/workspace.py +++ b/BEdit/src/bedit/gui/graphics/workspace.py @@ -1,10 +1,12 @@ import json +from dataclasses import dataclass from PySide6.QtCore import QMimeData, QPointF, QRectF, Qt, Signal from PySide6.QtGui import ( QColor, QDragEnterEvent, QDropEvent, + QKeyEvent, QMouseEvent, QWheelEvent, QPainter, @@ -32,17 +34,26 @@ from PySide6.QtWidgets import ( from bedit.core.model import Annotation, Component, Connection, Endpoint, Port from bedit.gui.controllers.document import DocumentController +from bedit.gui.dialogs.connection_chooser import ConnectionChooserDialog from bedit.gui.models.library_tree import COMPONENT_MIME_TYPE from bedit.gui.graphics.icon_renderer import icon_bounds, paint_icon from bedit.gui.graphics.icon_editor import ShapeOptionsDialog from bedit.gui.graphics.icon_renderer import shape_pen from bedit.gui.graphics.connection_styles import ConnectionStyle, connection_style from bedit.gui.preferences import application_settings +from bedit.core.port_types import PortTypeRegistry SELECTION_MIME_TYPE = "application/x-bedit-selection" +@dataclass(frozen=True) +class ConnectionChoice: + source: Endpoint + target: Endpoint + label: str + + def _graph_snap_size() -> int: return application_settings().value("grid/graphSnapSize", 8, type=int) @@ -690,11 +701,10 @@ class GraphScene(QGraphicsScene): self.output_items: dict[str, InterfaceTerminalItem] = {} self.connection_items: dict[str, ConnectionGraphicsItem] = {} self.annotation_items: dict[str, QGraphicsItem] = {} - self.pending_source: ConnectionPortItem | None = None + self.pending_connection_item: ComponentGraphicsItem | ConnectionPortItem | None = None self.pending_waypoints: list[QPointF] = [] self.pending_preview: QGraphicsPathItem | None = None self.interaction_mode = "pointer" - self.connection_routing = "angled" self.drawing_start: QPointF | None = None self.drawing_waypoints: list[QPointF] = [] self.setSceneRect(-2000, -2000, 4000, 4000) @@ -713,7 +723,7 @@ class GraphScene(QGraphicsScene): self.output_items.clear() self.connection_items.clear() self.annotation_items.clear() - self.pending_source = None + self.pending_connection_item = None self.pending_waypoints.clear() self.pending_preview = None owner = self.controller.active_component @@ -753,6 +763,7 @@ class GraphScene(QGraphicsScene): item = AnnotationGraphicsItem(annotation, self.controller) self.addItem(item) self.annotation_items[annotation.id] = item + self._set_port_hints_visible(self.interaction_mode == "connect") def set_component_position(self, component_id: str, position: QPointF) -> None: item = self.component_items.get(component_id) @@ -837,23 +848,65 @@ class GraphScene(QGraphicsScene): ports = component.output_ports if role == "source" else component.input_ports return ports.get(endpoint.port or "") + @staticmethod + def _hitbox_intersection(component: ComponentGraphicsItem, reference: QPointF) -> QPointF: + rect = component.hitbox.normalized() + local = component.mapFromScene(reference) + center = rect.center() + delta = local - center + if delta.isNull(): + return component.mapToScene(QPointF(rect.right(), center.y())) + scales: list[float] = [] + if delta.x() != 0: + scales.append((rect.width() / 2) / abs(delta.x())) + if delta.y() != 0: + scales.append((rect.height() / 2) / abs(delta.y())) + return component.mapToScene(center + delta * min(scales)) + + def _endpoint_center(self, endpoint: Endpoint, role: str) -> QPointF | None: + if endpoint.block is not None: + component = self.component_items.get(endpoint.block) + return component.mapToScene(component.hitbox.center()) if component else None + port = self._endpoint_item(endpoint, role) + return port.scenePos() if port else None + + def _visible_endpoint( + self, endpoint: Endpoint, role: str, reference: QPointF + ) -> QPointF | None: + if endpoint.block is not None: + component = self.component_items.get(endpoint.block) + return self._hitbox_intersection(component, reference) if component else None + port = self._endpoint_item(endpoint, role) + return port.scenePos() if port else None + + def _connection_geometry( + self, connection: Connection, waypoints: list[QPointF] + ) -> tuple[QPointF, QPointF] | None: + source_center = self._endpoint_center(connection.source, "source") + target_center = self._endpoint_center(connection.target, "target") + if source_center is None or target_center is None: + return None + start_reference = waypoints[0] if waypoints else target_center + end_reference = waypoints[-1] if waypoints else source_center + start = self._visible_endpoint(connection.source, "source", start_reference) + end = self._visible_endpoint(connection.target, "target", end_reference) + return (start, end) if start is not None and end is not None else None + def update_connection(self, connection_id: str) -> None: connection = self.controller.active_graph.connections.get(connection_id) graphics = self.connection_items.get(connection_id) if connection is None or graphics is None: return - source = self._endpoint_item(connection.source, "source") - target = self._endpoint_item(connection.target, "target") - if source is None or target is None: - return - start, end = source.scenePos(), target.scenePos() - routing = str(connection.properties.get("routing", "angled")) waypoints = [ QPointF(float(point["x"]), float(point["y"])) for point in connection.properties.get("waypoints", []) if isinstance(point, dict) and "x" in point and "y" in point ] - path, direction_points = self._route_path(start, end, routing, waypoints) + geometry = self._connection_geometry(connection, waypoints) + if geometry is None: + return + start, end = geometry + path, direction_points = self._route_path(start, end, waypoints) graphics.set_connection_path(path, direction_points) graphics.set_waypoints(waypoints) @@ -868,112 +921,193 @@ class GraphScene(QGraphicsScene): QPointF(float(p["x"]), float(p["y"])) for p in annotation.properties.get("waypoints", []) ] - routing = str(annotation.properties.get("routing", "angled")) - path, points = self._route_path(start, end, routing, waypoints) + path, points = self._route_path(start, end, waypoints) graphics.setPath(path) graphics.set_waypoints(waypoints, start, end) - @staticmethod - def _orthogonal_points(start: QPointF, end: QPointF, waypoints: list[QPointF]) -> list[QPointF]: - points = [start] - for waypoint in [*waypoints, end]: - previous = points[-1] - if previous.x() != waypoint.x() and previous.y() != waypoint.y(): - elbow = QPointF(waypoint.x(), previous.y()) - points.append(elbow) - if waypoint != points[-1]: - points.append(waypoint) - return points - @staticmethod def _route_path( start: QPointF, end: QPointF, - routing: str, waypoints: list[QPointF] | None = None, ) -> tuple[QPainterPath, list[QPointF]]: - waypoints = waypoints or [] + points = [start, *(waypoints or []), end] path = QPainterPath(start) - if routing == "angled": - points = GraphScene._orthogonal_points(start, end, waypoints) - for point in points[1:]: - path.lineTo(point) - return path, points - if routing == "direct": - path.lineTo(end) - return path, [start, end] - if waypoints: - points = [start, *waypoints, end] - for index, point in enumerate(points[1:-1], start=1): - following = points[index + 1] - midpoint = QPointF((point.x() + following.x()) / 2, (point.y() + following.y()) / 2) - path.quadTo(point, midpoint) - path.quadTo(points[-2], end) - return path, points - distance = max(50.0, abs(end.x() - start.x()) * 0.5) - first_control, second_control = start + QPointF(distance, 0), end - QPointF(distance, 0) - path.cubicTo(first_control, second_control, end) - return path, [start, first_control, second_control, end] + for point in points[1:]: + path.lineTo(point) + return path, points def set_interaction_mode(self, mode: str) -> None: self.interaction_mode = mode if mode != "connect": - self._clear_pending_source() + self._clear_pending_connection() self._clear_drawing() + self._set_port_hints_visible(mode == "connect") - def set_connection_routing(self, routing: str) -> None: - self.connection_routing = routing - self._clear_pending_source() + def _set_port_hints_visible(self, visible: bool) -> None: + for component in self.component_items.values(): + for port in (*component.input_ports.values(), *component.output_ports.values()): + port.setVisible(visible) + for terminal in (*self.input_items.values(), *self.output_items.values()): + terminal.connection_port.setVisible(visible) + + @staticmethod + def _clicked_component( + item: QGraphicsItem | None, + ) -> ComponentGraphicsItem | None: + if isinstance(item, ComponentGraphicsItem): + return item + if isinstance(item, ConnectionPortItem) and isinstance( + item.parentItem(), ComponentGraphicsItem + ): + return item.parentItem() + return None + + @staticmethod + def _click_endpoint(item: QGraphicsItem | None) -> Endpoint | None: + return item.endpoint if isinstance(item, ConnectionPortItem) else None + + @staticmethod + def _connection_anchor( + item: ComponentGraphicsItem | ConnectionPortItem, + ) -> QPointF: + return ( + item.scenePos() + if isinstance(item, ConnectionPortItem) + else item.sceneBoundingRect().center() + ) + + def _connection_choices( + self, + first: ComponentGraphicsItem, + second: ComponentGraphicsItem, + ) -> list[ConnectionChoice]: + choices: list[ConnectionChoice] = [] + + def add_pairs( + source_item: ComponentGraphicsItem, target_item: ComponentGraphicsItem + ) -> None: + for output in source_item.component.outputs: + for input_port in target_item.component.inputs: + if not PortTypeRegistry.compatible(output.type, input_port.type): + continue + choices.append( + ConnectionChoice( + Endpoint(block=source_item.component_id, port=output.id), + Endpoint(block=target_item.component_id, port=input_port.id), + f"{source_item.component.name}.{output.name} → " + f"{target_item.component.name}.{input_port.name}", + ) + ) + + add_pairs(first, second) + add_pairs(second, first) + return choices + + @staticmethod + def _default_choice_index( + choices: list[ConnectionChoice], + first_component: ComponentGraphicsItem, + second_component: ComponentGraphicsItem, + first_endpoint: Endpoint | None, + second_endpoint: Endpoint | None, + ) -> int: + def score(choice: ConnectionChoice) -> int: + value = 0 + if first_endpoint is not None and first_endpoint in (choice.source, choice.target): + value += 8 + if second_endpoint is not None and second_endpoint in (choice.source, choice.target): + value += 8 + if choice.source.block == first_component.component_id: + value += 2 + if choice.target.block == second_component.component_id: + value += 1 + return value + + return max(range(len(choices)), key=lambda index: score(choices[index])) + + def _finish_block_connection( + self, + second_item: ComponentGraphicsItem | ConnectionPortItem, + ) -> None: + first_item = self.pending_connection_item + if first_item is None: + return + first_component = self._clicked_component(first_item) + second_component = self._clicked_component(second_item) + if ( + first_component is None + or second_component is None + or first_component is second_component + ): + self._clear_pending_connection() + return + choices = self._connection_choices(first_component, second_component) + if not choices: + QToolTip.showText( + self.views()[0].mapToGlobal(self.views()[0].viewport().rect().center()) + if self.views() + else QPointF().toPoint(), + "These blocks have no compatible input/output pairs", + ) + self._clear_pending_connection() + return + default = self._default_choice_index( + choices, + first_component, + second_component, + self._click_endpoint(first_item), + self._click_endpoint(second_item), + ) + dialog = ConnectionChooserDialog( + [choice.label for choice in choices], + default, + self.views()[0] if self.views() else None, + ) + if dialog.exec() == dialog.DialogCode.Accepted: + choice = choices[dialog.selected_index] + try: + self.controller.connect( + choice.source, choice.target, waypoints=self.pending_waypoints + ) + except ValueError as error: + QToolTip.showText(dialog.mapToGlobal(dialog.rect().center()), str(error)) + self._clear_pending_connection() def mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802 if self.interaction_mode in {"box", "text", "line"}: self._drawing_press(event) return if self.interaction_mode != "connect": - self._clear_pending_source() + self._clear_pending_connection() super().mousePressEvent(event) return if event.button() == Qt.MouseButton.RightButton: - self._clear_pending_source() + self._clear_pending_connection() event.accept() return item = self.itemAt(event.scenePos(), QTransform()) - if isinstance(item, ConnectionPortItem): - if item.role == "source": - self._clear_pending_source() - self.pending_source = item + component = self._clicked_component(item) + if component is not None: + clicked = item if isinstance(item, ConnectionPortItem) else component + if self.pending_connection_item is None: + self.pending_connection_item = clicked self.pending_waypoints = [] - item.setBrush(QColor("#f5b642")) + if isinstance(clicked, ConnectionPortItem): + clicked.setBrush(QColor("#f5b642")) self._create_preview() - elif self.pending_source is not None: - if self.pending_source.endpoint != item.endpoint: - try: - self.controller.connect( - self.pending_source.endpoint, - item.endpoint, - routing=self.connection_routing, - waypoints=( - self._completed_angled_waypoints( - self.pending_source.scenePos(), - item.scenePos(), - self.pending_waypoints, - ) - if self.connection_routing == "angled" - else self.pending_waypoints - ), - ) - except ValueError as error: - QToolTip.showText(event.screenPos(), str(error)) - self._clear_pending_source() + self._update_preview(event.scenePos()) + else: + self._finish_block_connection(clicked) event.accept() return - if self.pending_source is not None and self.connection_routing == "angled": + if self.pending_connection_item is not None: self.pending_waypoints.append(_snapped(event.scenePos())) self._update_preview(event.scenePos()) event.accept() def mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802 - if self.interaction_mode == "connect" and self.pending_source is not None: + if self.interaction_mode == "connect" and self.pending_connection_item is not None: self._update_preview(event.scenePos()) event.accept() return @@ -1011,14 +1145,9 @@ class GraphScene(QGraphicsScene): self.drawing_start = point self.drawing_waypoints = [] self._create_preview() - elif self.interaction_mode == "line" and self.connection_routing == "angled": + elif self.interaction_mode == "line": self.drawing_waypoints.append(point) self._update_drawing_preview(point) - elif self.interaction_mode == "line": - self.controller.add_annotation( - "line", self.drawing_start, point, routing=self.connection_routing - ) - self._clear_drawing() event.accept() def mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent) -> None: # noqa: N802 @@ -1029,21 +1158,12 @@ class GraphScene(QGraphicsScene): if self.drawing_waypoints and self.drawing_waypoints[-1] == end else self.drawing_waypoints ) - completed = self._completed_angled_waypoints(self.drawing_start, end, waypoints) - self.controller.add_annotation( - "line", self.drawing_start, end, routing="angled", waypoints=completed - ) + self.controller.add_annotation("line", self.drawing_start, end, waypoints=waypoints) self._clear_drawing() event.accept() return super().mouseDoubleClickEvent(event) - @staticmethod - def _completed_angled_waypoints( - start: QPointF, end: QPointF, waypoints: list[QPointF] - ) -> list[QPointF]: - return GraphScene._orthogonal_points(start, end, waypoints)[1:-1] - def _update_drawing_preview(self, cursor: QPointF) -> None: if self.drawing_start is None or self.pending_preview is None: return @@ -1052,13 +1172,11 @@ class GraphScene(QGraphicsScene): path = QPainterPath() path.addRect(QRectF(self.drawing_start, end).normalized()) else: - path, _ = self._route_path( - self.drawing_start, end, self.connection_routing, self.drawing_waypoints - ) + path, _ = self._route_path(self.drawing_start, end, self.drawing_waypoints) self.pending_preview.setPath(path) def _clear_drawing(self) -> None: - if self.pending_preview is not None and self.pending_source is None: + if self.pending_preview is not None and self.pending_connection_item is None: self.removeItem(self.pending_preview) self.pending_preview = None self.drawing_start = None @@ -1118,10 +1236,7 @@ class GraphScene(QGraphicsScene): key=lambda index: segment_distance(snapped, anchors[index], anchors[index + 1]), ) points.insert(insertion, snapped) - routing = "angled" if item.properties.get("routing") == "direct" else None - if routing == "angled" or item.properties.get("routing") == "angled": - points = self._orthogonal_points(start, end, points)[1:-1] - self.controller.set_route_waypoints(item_kind, item_id, points, routing) + self.controller.set_route_waypoints(item_kind, item_id, points) def move_route_node(self, item_kind: str, item_id: str, index: int, position: QPointF) -> None: item, points = self._route_values(item_kind, item_id) @@ -1147,14 +1262,6 @@ class GraphScene(QGraphicsScene): return if index < len(points): points[index] = position - if item.properties.get("routing") == "angled": - if item_kind == "annotation": - start = QPointF(item.x, item.y) - end = QPointF(item.x + item.width, item.y + item.height) - else: - graphics = self.connection_items[item_id] - start, end = graphics.start, graphics.end - points = self._orthogonal_points(start, end, points)[1:-1] self.controller.set_route_waypoints(item_kind, item_id, points) def preview_route_node( @@ -1169,23 +1276,20 @@ class GraphScene(QGraphicsScene): return start = position if index == -1 else QPointF(item.x, item.y) end = position if index == -2 else QPointF(item.x + item.width, item.y + item.height) - path, _direction_points = self._route_path( - start, - end, - str(item.properties.get("routing", "angled")), - points, - ) + path, _direction_points = self._route_path(start, end, points) graphics.setPath(path) return if index >= len(points): return points[index] = position - routing = str(item.properties.get("routing", "angled")) if item_kind == "connection": graphics = self.connection_items.get(item_id) if graphics is None: return - path, direction_points = self._route_path(graphics.start, graphics.end, routing, points) + geometry = self._connection_geometry(item, points) + if geometry is None: + return + path, direction_points = self._route_path(*geometry, points) graphics.set_connection_path(path, direction_points) return graphics = self.annotation_items.get(item_id) @@ -1193,7 +1297,7 @@ class GraphScene(QGraphicsScene): return start = QPointF(item.x, item.y) end = QPointF(item.x + item.width, item.y + item.height) - path, _direction_points = self._route_path(start, end, routing, points) + path, _direction_points = self._route_path(start, end, points) graphics.setPath(path) def delete_route_node(self, item_kind: str, item_id: str, index: int) -> None: @@ -1217,29 +1321,29 @@ class GraphScene(QGraphicsScene): self.addItem(self.pending_preview) def _update_preview(self, cursor: QPointF) -> None: - if self.pending_source is None or self.pending_preview is None: + if self.pending_connection_item is None or self.pending_preview is None: return - preview_cursor = _snapped(cursor) if self.connection_routing == "angled" else cursor + preview_cursor = _snapped(cursor) path, _points = self._route_path( - self.pending_source.scenePos(), + self._connection_anchor(self.pending_connection_item), preview_cursor, - self.connection_routing, self.pending_waypoints, ) self.pending_preview.setPath(path) - def _clear_pending_source(self) -> None: - if self.pending_source is not None: - self.pending_source.setBrush(QColor("#ffffff")) + def _clear_pending_connection(self) -> None: + if isinstance(self.pending_connection_item, ConnectionPortItem): + self.pending_connection_item.setBrush(QColor("#ffffff")) if self.pending_preview is not None: self.removeItem(self.pending_preview) - self.pending_source = None + self.pending_connection_item = None self.pending_waypoints.clear() self.pending_preview = None class GraphWorkspaceView(QGraphicsView): toolUsed = Signal() + toolModeShortcutRequested = Signal(str) componentOptionsRequested = Signal(str) componentPortOptionsRequested = Signal(str) portOptionsRequested = Signal(str, str) @@ -1252,6 +1356,7 @@ class GraphWorkspaceView(QGraphicsView): self.tool_mode = "pointer" self.paste_count = 0 self.setAcceptDrops(True) + self.setFocusPolicy(Qt.FocusPolicy.StrongFocus) self.setMouseTracking(True) self.setRenderHint(QPainter.RenderHint.Antialiasing) self.setDragMode(QGraphicsView.DragMode.RubberBandDrag) @@ -1304,6 +1409,23 @@ class GraphWorkspaceView(QGraphicsView): self._zoom(1.2 if event.angleDelta().y() > 0 else 1 / 1.2) event.accept() + def keyPressEvent(self, event: QKeyEvent) -> None: # noqa: N802 + if not event.isAutoRepeat() and event.key() == Qt.Key.Key_Space: + self.toolModeShortcutRequested.emit( + "connect" if self.tool_mode == "pointer" else "pointer" + ) + event.accept() + return + if ( + not event.isAutoRepeat() + and event.key() == Qt.Key.Key_Escape + and self.tool_mode != "pointer" + ): + self.toolModeShortcutRequested.emit("pointer") + event.accept() + return + super().keyPressEvent(event) + def set_model(self, controller: DocumentController) -> None: self.controller = controller scene = GraphScene(controller, self) @@ -1445,11 +1567,6 @@ class GraphWorkspaceView(QGraphicsView): if isinstance(scene, GraphScene): scene.set_interaction_mode(mode) - def set_connection_routing(self, routing: str) -> None: - scene = self.scene() - if isinstance(scene, GraphScene): - scene.set_connection_routing(routing) - def mousePressEvent(self, event: QMouseEvent) -> None: # noqa: N802 super().mousePressEvent(event) diff --git a/BEdit/src/bedit/gui/main_window.py b/BEdit/src/bedit/gui/main_window.py index d1396b7..17295dd 100644 --- a/BEdit/src/bedit/gui/main_window.py +++ b/BEdit/src/bedit/gui/main_window.py @@ -92,6 +92,7 @@ class MainWindow(QMainWindow): self.ui.graphView.selectionAvailabilityChanged.connect( lambda _available: self._update_edit_actions() ) + self.ui.graphView.toolModeShortcutRequested.connect(self.set_graph_tool) self.mode_button_group = QButtonGroup(self) self.mode_button_group.setExclusive(True) self.mode_button_group.addButton(self.ui.pointerToolButton) @@ -99,14 +100,6 @@ class MainWindow(QMainWindow): self.mode_button_group.addButton(self.ui.boxToolButton) self.mode_button_group.addButton(self.ui.lineToolButton) self.mode_button_group.addButton(self.ui.textToolButton) - self.routing_button_group = QButtonGroup(self) - self.routing_button_group.setExclusive(True) - for button in ( - self.ui.directRoutingButton, - self.ui.angledRoutingButton, - self.ui.splineRoutingButton, - ): - self.routing_button_group.addButton(button) self.ui.navigateUpButton.clicked.connect(self.navigate_up) self.ui.navigateDownButton.clicked.connect(self.navigate_down) self.ui.pointerToolButton.clicked.connect(lambda: self.set_graph_tool("pointer")) @@ -115,9 +108,6 @@ class MainWindow(QMainWindow): self.ui.lineToolButton.clicked.connect(lambda: self.set_graph_tool("line")) self.ui.textToolButton.clicked.connect(lambda: self.set_graph_tool("text")) self.ui.rotateToolButton.clicked.connect(self.ui.graphView.rotate_selected) - self.ui.directRoutingButton.clicked.connect(lambda: self.set_connection_routing("direct")) - self.ui.angledRoutingButton.clicked.connect(lambda: self.set_connection_routing("angled")) - self.ui.splineRoutingButton.clicked.connect(lambda: self.set_connection_routing("spline")) self.ui.applyJsonButton.clicked.connect(self.apply_json) self.document_controller.activeGraphChanged.connect(self._active_graph_changed) @@ -255,10 +245,6 @@ class MainWindow(QMainWindow): self.ui.lineToolButton, self.ui.textToolButton, self.ui.rotateToolButton, - self.ui.routingLabel, - self.ui.directRoutingButton, - self.ui.angledRoutingButton, - self.ui.splineRoutingButton, ): widget.setVisible(visible) @@ -272,15 +258,6 @@ class MainWindow(QMainWindow): "text": self.ui.textToolButton, }[mode].setChecked(True) - def set_connection_routing(self, routing: str) -> None: - self.ui.graphView.set_connection_routing(routing) - buttons = { - "direct": self.ui.directRoutingButton, - "angled": self.ui.angledRoutingButton, - "spline": self.ui.splineRoutingButton, - } - buttons[routing].setChecked(True) - def _load_source_json(self) -> None: component = self.document_controller.active_component if component is None: diff --git a/BEdit/ui/connection_chooser_dialog.ui b/BEdit/ui/connection_chooser_dialog.ui new file mode 100644 index 0000000..57fb111 --- /dev/null +++ b/BEdit/ui/connection_chooser_dialog.ui @@ -0,0 +1,19 @@ + + + ConnectionChooserDialog + + 00460280 + Select a Connection + + Select a connection: + true + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + buttonBoxaccepted()ConnectionChooserDialogaccept() + buttonBoxrejected()ConnectionChooserDialogreject() + connectionListitemDoubleClicked(QListWidgetItem*)ConnectionChooserDialogaccept() + + diff --git a/BEdit/ui/icon_editor_dialog.ui b/BEdit/ui/icon_editor_dialog.ui index c59f54a..b90b4f0 100644 --- a/BEdit/ui/icon_editor_dialog.ui +++ b/BEdit/ui/icon_editor_dialog.ui @@ -2,35 +2,260 @@ IconEditorDialog - 00850600 - Icon Editor + + + 0 + 0 + 850 + 600 + + + + Icon Editor + - Pointertruetrue - Add: - Rectangletrue - Circletrue - Ellipsetrue - Linetrue - Triangletrue - Texttrue - Qt::Orientation::Horizontal4020 - +Zoom in - Zoom out - FitFit and center the icon canvas - Delete selected + + + + Pointer + + + + :/icons/icons/edit-select.png:/icons/icons/edit-select.png + + + true + + + true + + + + + + + Add: + + + + + + + Rectangle + + + + :/icons/icons/draw-rectangle.png:/icons/icons/draw-rectangle.png + + + true + + + + + + + Circle + + + + :/icons/icons/draw-circle.png:/icons/icons/draw-circle.png + + + true + + + + + + + Ellipse + + + + :/icons/icons/draw-ellipse.png:/icons/icons/draw-ellipse.png + + + true + + + + + + + Line + + + + :/icons/icons/draw-bezier-curves.png:/icons/icons/draw-bezier-curves.png + + + true + + + + + + + Triangle + + + + :/icons/icons/draw-triangle.png:/icons/icons/draw-triangle.png + + + true + + + + + + + Text + + + + :/icons/icons/draw-text.png:/icons/icons/draw-text.png + + + true + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + Zoom in + + + + + + + + :/icons/icons/zoom-in.png:/icons/icons/zoom-in.png + + + + + + + Zoom out + + + + + + + :/icons/icons/zoom-out.png:/icons/icons/zoom-out.png + + + + + + + Fit and center the icon canvas + + + Fit + + + + :/icons/icons/zoom-original.png:/icons/icons/zoom-original.png + + + + + + + Delete selected + + + - QGraphicsView::DragMode::RubberBandDrag - Green points are inputs; red points are outputs. Drag them to place connection anchors.true - QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + QGraphicsView::DragMode::RubberBandDrag + + + + + + + Green points are inputs; red points are outputs. Drag them to place connection anchors. + + + true + + + + + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + - IconCanvasViewQGraphicsView
bedit.gui.graphics.icon_canvas
- + + + IconCanvasView + QGraphicsView +
bedit.gui.graphics.icon_canvas
+
+
+ + + - buttonBoxaccepted()IconEditorDialogaccept() - buttonBoxrejected()IconEditorDialogreject() + + buttonBox + accepted() + IconEditorDialog + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonBox + rejected() + IconEditorDialog + reject() + + + 20 + 20 + + + 20 + 20 + + +
diff --git a/BEdit/ui/main_window.ui b/BEdit/ui/main_window.ui index ab5950d..28b604f 100644 --- a/BEdit/ui/main_window.ui +++ b/BEdit/ui/main_window.ui @@ -296,6 +296,10 @@ Connect + + + :/icons/icons/network-connect.png:/icons/icons/network-connect.png + true @@ -366,46 +370,6 @@ - - - - Line: - - - - - - - Direct - - - true - - - - - - - Angled - - - true - - - true - - - - - - - Spline - - - true - - - diff --git a/BEdit/untitled.bedit.json b/BEdit/untitled.bedit.json index f133eb5..265e714 100644 --- a/BEdit/untitled.bedit.json +++ b/BEdit/untitled.bedit.json @@ -63,8 +63,8 @@ "id": "af73487a-4a2d-4908-b919-d0a2eaa75ce2", "name": "A", "position": { - "x": -192.0, - "y": -192.0 + "x": -224.0, + "y": -168.0 }, "rotation": 0.0, "interface": { @@ -157,8 +157,8 @@ "id": "b89a77a1-d773-4ee3-8c3f-74377c29b4b2", "name": "B", "position": { - "x": 128.0, - "y": -128.0 + "x": 96.0, + "y": -288.0 }, "rotation": 0.0, "interface": { @@ -266,7 +266,7 @@ ], "connections": [ { - "id": "c59eac1f-5f24-45de-90ee-bfd039894ed9", + "id": "87490296-e353-43ea-8b59-55329950fdce", "source": { "block": "af73487a-4a2d-4908-b919-d0a2eaa75ce2", "port": "port-de109124" @@ -277,85 +277,24 @@ }, "name": "", "properties": { - "routing": "angled", "waypoints": [ { "x": -64.0, - "y": -128.0 + "y": -192.0 }, { "x": -64.0, - "y": 64.0 - }, - { - "x": 0.0, - "y": 64.0 - }, - { - "x": 0.0, - "y": 120.0 + "y": -256.0 }, { "x": 64.0, - "y": 120.0 - }, - { - "x": 64.0, - "y": -80.0 + "y": -256.0 } ] } } ], - "annotations": [ - { - "id": "bfe7d48b-fe54-4378-ab1b-f9b46c2efa87", - "kind": "box", - "position": { - "x": 48.0, - "y": -328.0 - }, - "size": { - "width": 304.0, - "height": 160.0 - }, - "text": "", - "layer": -1, - "properties": { - "stroke": "#303030", - "lineWidth": 1.5, - "lineStyle": "solid", - "fill": "#dbeafe", - "cornerRadius": 0.0, - "routing": "angled", - "waypoints": [] - } - }, - { - "id": "aa69f7b3-f5af-426b-9eb3-c63a268346b5", - "kind": "text", - "position": { - "x": -272.0, - "y": -216.0 - }, - "size": { - "width": 400.0, - "height": 48.0 - }, - "text": "This is an annotation", - "layer": -1, - "properties": { - "stroke": "#023010", - "lineWidth": 3.0, - "lineStyle": "dash", - "fill": "none", - "fontSize": 18.0, - "color": "#023010", - "routing": "angled", - "waypoints": [] - } - } - ] + "annotations": [] } } }