Integrate typed ports and schema 3 migration
# Conflicts: # crates/oa-core/src/projection.rs
This commit is contained in:
@@ -20,6 +20,7 @@ pub struct ProjectedEdge {
|
||||
pub source: Id,
|
||||
pub target: Id,
|
||||
pub trace: bool,
|
||||
pub oriented: bool,
|
||||
pub source_port: Option<Id>,
|
||||
pub target_port: Option<Id>,
|
||||
}
|
||||
@@ -29,7 +30,36 @@ pub struct ProjectedPort {
|
||||
/// Placement identity of the owning visible function/participant.
|
||||
pub owner: Id,
|
||||
pub position: Position,
|
||||
pub direction: PortDirection,
|
||||
pub side: PortAnchorSide,
|
||||
}
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum PortAnchorSide {
|
||||
Left,
|
||||
Right,
|
||||
Bottom,
|
||||
}
|
||||
pub fn port_anchor_side(e: &Element) -> Option<PortAnchorSide> {
|
||||
let Some(SharedBody::Port { contract, legacy }) = e.shared() else {
|
||||
return None;
|
||||
};
|
||||
Some(match contract {
|
||||
PortContract::FunctionInput { .. } => PortAnchorSide::Left,
|
||||
PortContract::FunctionOutput { .. } => PortAnchorSide::Right,
|
||||
PortContract::Component {
|
||||
kind: ComponentPortKind::Flow,
|
||||
orientation: ComponentPortOrientation::In,
|
||||
} => PortAnchorSide::Left,
|
||||
PortContract::Component {
|
||||
kind: ComponentPortKind::Flow,
|
||||
orientation: ComponentPortOrientation::Out,
|
||||
} => PortAnchorSide::Right,
|
||||
PortContract::Legacy => match legacy.as_ref().map(|l| l.direction) {
|
||||
Some(PortDirection::In) => PortAnchorSide::Left,
|
||||
Some(PortDirection::Out) => PortAnchorSide::Right,
|
||||
_ => PortAnchorSide::Bottom,
|
||||
},
|
||||
_ => PortAnchorSide::Bottom,
|
||||
})
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
|
||||
pub struct ProjectedView {
|
||||
@@ -38,10 +68,25 @@ pub struct ProjectedView {
|
||||
pub ports: Vec<ProjectedPort>,
|
||||
}
|
||||
pub(crate) fn minimum_node_size(p: &Project, element: Id, mut size: Size) -> Size {
|
||||
let count = [PortDirection::In, PortDirection::Out].into_iter().map(|direction| p.children(element).filter(|port| matches!(port.shared(), Some(SharedBody::Port {direction:d,..}) if *d==direction)).count()).max().unwrap_or(0);
|
||||
let count = [PortAnchorSide::Left, PortAnchorSide::Right]
|
||||
.into_iter()
|
||||
.map(|side| {
|
||||
p.children(element)
|
||||
.filter(|port| port_anchor_side(port) == Some(side))
|
||||
.count()
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
if count > 0 {
|
||||
size.height = size.height.max(76. + 28. * (count + 1) as f32);
|
||||
}
|
||||
let bottom = p
|
||||
.children(element)
|
||||
.filter(|port| port_anchor_side(port) == Some(PortAnchorSide::Bottom))
|
||||
.count();
|
||||
if bottom > 0 {
|
||||
size.width = size.width.max(28. * (bottom + 1) as f32);
|
||||
}
|
||||
size
|
||||
}
|
||||
pub(crate) fn port_footer(p: &Project, element: Id) -> f32 {
|
||||
@@ -250,8 +295,15 @@ pub fn project_diagram(p: &Project, d: &Diagram) -> ProjectedView {
|
||||
.filter(|e| e.kind() == Kind::Port)
|
||||
.collect();
|
||||
children.sort_by_key(|e| (&e.alias, e.id));
|
||||
for direction in [PortDirection::In, PortDirection::Out, PortDirection::InOut] {
|
||||
let side: Vec<_> = children.iter().filter(|e| matches!(e.shared(), Some(SharedBody::Port {direction: d, ..}) if *d == direction)).collect();
|
||||
for anchor_side in [
|
||||
PortAnchorSide::Left,
|
||||
PortAnchorSide::Right,
|
||||
PortAnchorSide::Bottom,
|
||||
] {
|
||||
let side: Vec<_> = children
|
||||
.iter()
|
||||
.filter(|e| port_anchor_side(e) == Some(anchor_side))
|
||||
.collect();
|
||||
for (index, port) in side.iter().enumerate() {
|
||||
let fraction = (index + 1) as f32 / (side.len() + 1) as f32;
|
||||
let y = if p.elements[&node.element].kind().is_performer()
|
||||
@@ -263,16 +315,16 @@ pub fn project_diagram(p: &Project, d: &Diagram) -> ProjectedView {
|
||||
} else {
|
||||
node.position.y + 64. + (node.size.height - 76.).max(0.) * fraction
|
||||
};
|
||||
let position = match direction {
|
||||
PortDirection::In => Position {
|
||||
let position = match anchor_side {
|
||||
PortAnchorSide::Left => Position {
|
||||
x: node.position.x,
|
||||
y,
|
||||
},
|
||||
PortDirection::Out => Position {
|
||||
PortAnchorSide::Right => Position {
|
||||
x: node.position.x + node.size.width,
|
||||
y,
|
||||
},
|
||||
PortDirection::InOut => Position {
|
||||
PortAnchorSide::Bottom => Position {
|
||||
x: node.position.x + node.size.width * fraction,
|
||||
y: node.position.y + node.size.height,
|
||||
},
|
||||
@@ -281,7 +333,7 @@ pub fn project_diagram(p: &Project, d: &Diagram) -> ProjectedView {
|
||||
element: port.id,
|
||||
owner: node.id,
|
||||
position,
|
||||
direction,
|
||||
side: anchor_side,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -324,10 +376,9 @@ pub fn project_diagram(p: &Project, d: &Diagram) -> ProjectedView {
|
||||
source_port,
|
||||
target_port,
|
||||
..
|
||||
} => (*source_port, *target_port),
|
||||
RelationBody::BoundaryExchange { source, target, .. } => {
|
||||
(Some(*source), Some(*target))
|
||||
}
|
||||
} => (Some(*source_port), Some(*target_port)),
|
||||
RelationBody::BoundaryExchange { source, target, .. }
|
||||
| RelationBody::PortAllocation { source, target } => (Some(*source), Some(*target)),
|
||||
_ => (None, None),
|
||||
};
|
||||
edges.push(ProjectedEdge {
|
||||
@@ -335,6 +386,13 @@ pub fn project_diagram(p: &Project, d: &Diagram) -> ProjectedView {
|
||||
source,
|
||||
target,
|
||||
trace: false,
|
||||
oriented: !matches!(
|
||||
&r.body,
|
||||
RelationBody::BoundaryExchange {
|
||||
oriented: false,
|
||||
..
|
||||
}
|
||||
),
|
||||
source_port: source_port.filter(|id| ports.iter().any(|p| p.element == *id)),
|
||||
target_port: target_port.filter(|id| ports.iter().any(|p| p.element == *id)),
|
||||
});
|
||||
@@ -350,6 +408,7 @@ pub fn project_diagram(p: &Project, d: &Diagram) -> ProjectedView {
|
||||
source,
|
||||
target,
|
||||
trace: true,
|
||||
oriented: true,
|
||||
source_port: None,
|
||||
target_port: None,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user