Start with signal lib
This commit is contained in:
25
icons/signal_base.json
Normal file
25
icons/signal_base.json
Normal file
@@ -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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
55
icons/signal_source_base.json
Normal file
55
icons/signal_source_base.json
Normal file
@@ -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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
BIN
lib/signal.beb
Normal file
BIN
lib/signal.beb
Normal file
Binary file not shown.
BIN
lib/signal_sources.beb
Normal file
BIN
lib/signal_sources.beb
Normal file
Binary file not shown.
@@ -35,6 +35,7 @@ class LibraryController(QObject):
|
|||||||
tree.header().setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed)
|
tree.header().setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed)
|
||||||
tree.setColumnWidth(1, 56)
|
tree.setColumnWidth(1, 56)
|
||||||
|
|
||||||
|
window.ui.actionReload_Libraries.triggered.connect(self.reload)
|
||||||
self.reload()
|
self.reload()
|
||||||
|
|
||||||
def reload(self) -> None:
|
def reload(self) -> None:
|
||||||
|
|||||||
@@ -59,6 +59,7 @@
|
|||||||
<addaction name="actionDelete"/>
|
<addaction name="actionDelete"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionSettings"/>
|
<addaction name="actionSettings"/>
|
||||||
|
<addaction name="actionReload_Libraries"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuView">
|
<widget class="QMenu" name="menuView">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -351,6 +352,17 @@
|
|||||||
<string>Settings</string>
|
<string>Settings</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionReload_Libraries">
|
||||||
|
<property name="text">
|
||||||
|
<string>Reload Libraries</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reload configured libraries</string>
|
||||||
|
</property>
|
||||||
|
<property name="menuRole">
|
||||||
|
<enum>QAction::MenuRole::NoRole</enum>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
<action name="actionDelete">
|
<action name="actionDelete">
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../resources/resources.qrc">
|
<iconset resource="../../resources/resources.qrc">
|
||||||
|
|||||||
@@ -83,6 +83,9 @@ class Ui_MainWindow(object):
|
|||||||
self.actionToolbars.setObjectName(u"actionToolbars")
|
self.actionToolbars.setObjectName(u"actionToolbars")
|
||||||
self.actionSettings = QAction(MainWindow)
|
self.actionSettings = QAction(MainWindow)
|
||||||
self.actionSettings.setObjectName(u"actionSettings")
|
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 = QAction(MainWindow)
|
||||||
self.actionDelete.setObjectName(u"actionDelete")
|
self.actionDelete.setObjectName(u"actionDelete")
|
||||||
icon7 = QIcon()
|
icon7 = QIcon()
|
||||||
@@ -228,6 +231,7 @@ class Ui_MainWindow(object):
|
|||||||
self.menuEdit.addAction(self.actionDelete)
|
self.menuEdit.addAction(self.actionDelete)
|
||||||
self.menuEdit.addSeparator()
|
self.menuEdit.addSeparator()
|
||||||
self.menuEdit.addAction(self.actionSettings)
|
self.menuEdit.addAction(self.actionSettings)
|
||||||
|
self.menuEdit.addAction(self.actionReload_Libraries)
|
||||||
self.menuView.addAction(self.actionReset_Layout)
|
self.menuView.addAction(self.actionReset_Layout)
|
||||||
self.menuView.addAction(self.actionPanels)
|
self.menuView.addAction(self.actionPanels)
|
||||||
self.menuView.addAction(self.actionToolbars)
|
self.menuView.addAction(self.actionToolbars)
|
||||||
@@ -310,6 +314,10 @@ class Ui_MainWindow(object):
|
|||||||
self.actionPanels.setText(QCoreApplication.translate("MainWindow", u"Panels", None))
|
self.actionPanels.setText(QCoreApplication.translate("MainWindow", u"Panels", None))
|
||||||
self.actionToolbars.setText(QCoreApplication.translate("MainWindow", u"Toolbars", None))
|
self.actionToolbars.setText(QCoreApplication.translate("MainWindow", u"Toolbars", None))
|
||||||
self.actionSettings.setText(QCoreApplication.translate("MainWindow", u"Settings", 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))
|
self.actionDelete.setText(QCoreApplication.translate("MainWindow", u"Delete", None))
|
||||||
#if QT_CONFIG(tooltip)
|
#if QT_CONFIG(tooltip)
|
||||||
self.actionDelete.setToolTip(QCoreApplication.translate("MainWindow", u"Delete selected", None))
|
self.actionDelete.setToolTip(QCoreApplication.translate("MainWindow", u"Delete selected", None))
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from math import ceil
|
||||||
|
|
||||||
from PySide6.QtCore import QRectF, QSize, Qt
|
from PySide6.QtCore import QRectF, QSize, Qt
|
||||||
from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPainter, QPen, QPixmap, QRegion
|
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
|
PORT_SIZE = 16
|
||||||
DEFAULT_ICON_SIZE = QSize(48, 48)
|
DEFAULT_ICON_SIZE = QSize(48, 48)
|
||||||
|
EMPTY_NATURAL_ICON_SIZE = QSize(32, 32)
|
||||||
ICON_MARGIN = 4
|
ICON_MARGIN = 4
|
||||||
ICON_PREVIEW_OVERSAMPLE = 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())
|
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:
|
def render_icon(icon: Icon, ports: dict[PortID, Port], size: QSize = DEFAULT_ICON_SIZE, render_ports: bool = False) -> QIcon:
|
||||||
pixmap = QPixmap(size)
|
pixmap = QPixmap(size)
|
||||||
pixmap.fill(Qt.GlobalColor.transparent)
|
pixmap.fill(Qt.GlobalColor.transparent)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from enum import Enum
|
|||||||
from itertools import pairwise
|
from itertools import pairwise
|
||||||
from math import hypot
|
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.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
|
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.models import Graph, GraphComponentLabel, GraphConnection, Icon
|
||||||
from bedit_gui.services.component_clipboard import COMPONENTS_MIME
|
from bedit_gui.services.component_clipboard import COMPONENTS_MIME
|
||||||
from bedit_gui.ui.generated.ui_graph_editor_widget import Ui_graphEditorWidget
|
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
|
GRID_SPACING = 64
|
||||||
SCENE_SIZE = 10000
|
SCENE_SIZE = 10000
|
||||||
@@ -21,14 +21,18 @@ MIN_ZOOM = 0.2
|
|||||||
MAX_ZOOM = 4.0
|
MAX_ZOOM = 4.0
|
||||||
ZOOM_STEP = 1.15
|
ZOOM_STEP = 1.15
|
||||||
ZOOM_TO_FIT_PADDING = 32.0
|
ZOOM_TO_FIT_PADDING = 32.0
|
||||||
COMPONENT_ICON_SIZE = QSize(128, 128)
|
|
||||||
COMPONENT_LABEL_FONT_SIZE = 24.0
|
COMPONENT_LABEL_FONT_SIZE = 24.0
|
||||||
FALLBACK_COMPONENT_SPACING = 128
|
FALLBACK_COMPONENT_SPACING = 128
|
||||||
CONNECTION_WIDTH = 4.0
|
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
|
CONNECTION_STRAIGHTEN_TOLERANCE = 8.0
|
||||||
ARROW_LENGTH = 32.0
|
ARROW_LENGTH = 32.0
|
||||||
ARROW_HALF_WIDTH = 16.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
|
CAUSALITY_TICK_HALF_LENGTH = 16.0
|
||||||
|
|
||||||
|
|
||||||
@@ -66,8 +70,10 @@ class GraphConnectionItem(QGraphicsPathItem):
|
|||||||
self.connection_id = connection_id
|
self.connection_id = connection_id
|
||||||
self.editor = editor
|
self.editor = editor
|
||||||
self.setPath(self._connection_path(points, half_arrow, tick_at_source))
|
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.setPen(pen)
|
||||||
|
self.setBrush(QBrush(color))
|
||||||
self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
|
self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsSelectable)
|
||||||
self.setZValue(-1)
|
self.setZValue(-1)
|
||||||
|
|
||||||
@@ -100,15 +106,17 @@ class GraphConnectionItem(QGraphicsPathItem):
|
|||||||
dx = target.x() - previous.x()
|
dx = target.x() - previous.x()
|
||||||
dy = target.y() - previous.y()
|
dy = target.y() - previous.y()
|
||||||
length = hypot(dx, dy)
|
length = hypot(dx, dy)
|
||||||
back_x = target.x() - ARROW_LENGTH * dx / length
|
arrow_length = ARROW_LENGTH if half_arrow else SIGNAL_ARROW_LENGTH
|
||||||
back_y = target.y() - ARROW_LENGTH * dy / length
|
arrow_half_width = ARROW_HALF_WIDTH if half_arrow else SIGNAL_ARROW_HALF_WIDTH
|
||||||
perpendicular_x = -ARROW_HALF_WIDTH * dy / length
|
back_x = target.x() - arrow_length * dx / length
|
||||||
perpendicular_y = ARROW_HALF_WIDTH * 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.moveTo(target)
|
||||||
path.lineTo(back_x + perpendicular_x, back_y + perpendicular_y)
|
path.lineTo(back_x + perpendicular_x, back_y + perpendicular_y)
|
||||||
if not half_arrow:
|
if not half_arrow:
|
||||||
path.moveTo(target)
|
|
||||||
path.lineTo(back_x - perpendicular_x, back_y - perpendicular_y)
|
path.lineTo(back_x - perpendicular_x, back_y - perpendicular_y)
|
||||||
|
path.closeSubpath()
|
||||||
if tick_at_source is not None:
|
if tick_at_source is not None:
|
||||||
GraphConnectionItem._add_causality_tick(path, points, tick_at_source)
|
GraphConnectionItem._add_causality_tick(path, points, tick_at_source)
|
||||||
return path
|
return path
|
||||||
@@ -315,6 +323,7 @@ class GraphEditorWidget(QWidget):
|
|||||||
self.scene = GraphGraphicsScene(self)
|
self.scene = GraphGraphicsScene(self)
|
||||||
self.scene.setSceneRect(-SCENE_SIZE / 2, -SCENE_SIZE / 2, SCENE_SIZE, SCENE_SIZE)
|
self.scene.setSceneRect(-SCENE_SIZE / 2, -SCENE_SIZE / 2, SCENE_SIZE, SCENE_SIZE)
|
||||||
self.ui.graphicsView.setScene(self.scene)
|
self.ui.graphicsView.setScene(self.scene)
|
||||||
|
self.ui.graphicsView.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||||
self.ui.graphicsView.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
|
self.ui.graphicsView.setTransformationAnchor(QGraphicsView.ViewportAnchor.AnchorUnderMouse)
|
||||||
self.ui.graphicsView.viewport().installEventFilter(self)
|
self.ui.graphicsView.viewport().installEventFilter(self)
|
||||||
self.ui.graphicsView.viewport().setAcceptDrops(True)
|
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)}
|
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():
|
for component_id, child in component.implementation.graph.components.items():
|
||||||
icon = icons.get(component_id, Icon())
|
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 = GraphComponentItem(component_id, pixmap, self)
|
||||||
item.setOffset(-pixmap.width() / 2, -pixmap.height() / 2)
|
item.setOffset(-pixmap.width() / 2, -pixmap.height() / 2)
|
||||||
item.setPos(*positions[component_id])
|
item.setPos(*positions[component_id])
|
||||||
@@ -435,7 +445,8 @@ class GraphEditorWidget(QWidget):
|
|||||||
points = self._straighten_direct_connection(points)
|
points = self._straighten_direct_connection(points)
|
||||||
source_bounds = self._component_bounds[source_component].translated(*source_position)
|
source_bounds = self._component_bounds[source_component].translated(*source_position)
|
||||||
target_bounds = self._component_bounds[target_component].translated(*target_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
|
tick_at_source = None
|
||||||
if isinstance(connection, BondConnection):
|
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
|
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
|
return points
|
||||||
|
|
||||||
@staticmethod
|
@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]
|
source = points[0]
|
||||||
target = points[-1]
|
target = points[-1]
|
||||||
source_direction = next((point for point in points[1:] if point != source), None)
|
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:
|
if source_direction is None or target_direction is None:
|
||||||
return points
|
return points
|
||||||
clipped = list(points)
|
clipped = list(points)
|
||||||
clipped[0] = GraphEditorWidget._bounding_box_edge(source_bounds, source, source_direction)
|
clipped[0] = GraphEditorWidget._bounding_box_edge(source_bounds, source, source_direction, spacing)
|
||||||
clipped[-1] = GraphEditorWidget._bounding_box_edge(target_bounds, target, target_direction)
|
clipped[-1] = GraphEditorWidget._bounding_box_edge(target_bounds, target, target_direction, spacing)
|
||||||
return clipped
|
return clipped
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _bounding_box_edge(bounds: QRectF, origin: tuple[float, float], toward: tuple[float, float]) -> tuple[float, float]:
|
def _bounding_box_edge(bounds: QRectF, origin: tuple[float, float], toward: tuple[float, float], spacing: float) -> tuple[float, float]:
|
||||||
bounds = bounds.adjusted(-CONNECTION_BOUNDING_BOX_SPACING, -CONNECTION_BOUNDING_BOX_SPACING, CONNECTION_BOUNDING_BOX_SPACING, CONNECTION_BOUNDING_BOX_SPACING)
|
bounds = bounds.adjusted(-spacing, -spacing, spacing, spacing)
|
||||||
dx = toward[0] - origin[0]
|
dx = toward[0] - origin[0]
|
||||||
dy = toward[1] - origin[1]
|
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")
|
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))
|
self._connection_preview.setPath(QPainterPath(mouse_position))
|
||||||
return
|
return
|
||||||
bounds = self._component_bounds[self._connection_start].translated(*source)
|
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 = QPainterPath(QPointF(*start))
|
||||||
path.lineTo(mouse_position)
|
path.lineTo(mouse_position)
|
||||||
self._connection_preview.setPath(path)
|
self._connection_preview.setPath(path)
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ from PySide6.QtWidgets import QGraphicsItem, QGraphicsLineItem, QGraphicsPathIte
|
|||||||
from bedit_core.models import Port, PortID, SignalDirection
|
from bedit_core.models import Port, PortID, SignalDirection
|
||||||
from bedit_gui.models import Icon, Line, LineType, Rectangle, Shape, ShapeID, Text
|
from bedit_gui.models import Icon, Line, LineType, Rectangle, Shape, ShapeID, Text
|
||||||
|
|
||||||
|
ICON_SCENE_SIZE = 512
|
||||||
|
|
||||||
|
|
||||||
class ShapeCreationTool(Protocol):
|
class ShapeCreationTool(Protocol):
|
||||||
def begin(self, position: QPointF) -> None: ...
|
def begin(self, position: QPointF) -> None: ...
|
||||||
@@ -356,7 +358,7 @@ class IconGraphicsScene(QGraphicsScene):
|
|||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._tool: ShapeCreationTool | None = None
|
self._tool: ShapeCreationTool | None = None
|
||||||
self._ports: dict[PortID, Port] = {}
|
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:
|
def set_ports(self, ports: dict[PortID, Port]) -> None:
|
||||||
self._ports = deepcopy(ports)
|
self._ports = deepcopy(ports)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user