///|
pub fn add_border_segments(g : Graph) -> Unit {
if !g.is_compound() {
return
}
for v in g.children() {
add_bs_dfs(g, v)
}
}
///|
fn add_bs_dfs(g : Graph, v : String) -> Unit {
let children = g.children(v~)
let node = g.node(v)
if !children.is_empty() {
for child in children {
add_bs_dfs(g, child)
}
}
if node.get_int("minRank") is Some(min_rank) {
let max_rank = node.get_int_or("maxRank", min_rank)
node.set_strings("borderLeft", [])
node.set_strings("borderRight", [])
let mut rank = min_rank
while rank <= max_rank {
add_bs_border_node(g, "borderLeft", "_bl", v, node, rank)
add_bs_border_node(g, "borderRight", "_br", v, node, rank)
rank = rank + 1
}
}
}
///|
fn add_bs_border_node(
g : Graph,
prop : String,
prefix : String,
sg : String,
sg_node : Attrs,
rank : Int,
) -> Unit {
let label = empty_attrs()
label.set_float("width", 0.0)
label.set_float("height", 0.0)
label.set_int("rank", rank)
label.set_string("borderType", prop)
let prev = add_bs_border_at(sg_node, prop, rank - 1)
let curr = add_dummy_node(g, "border", label, prefix)
add_bs_set_border_at(sg_node, prop, rank, curr)
g.set_parent(curr, parent=sg)
if prev is Some(prev) {
let edge = empty_attrs()
edge.set_int("weight", 1)
g.set_edge(prev, curr, label=attrs_value(edge))
}
}
///|
fn add_bs_border_at(node : Attrs, prop : String, rank : Int) -> String? {
if node.get_strings(prop) is Some(border_nodes) {
if rank >= 0 && rank < border_nodes.length() {
let value = border_nodes[rank]
if value == "" {
None
} else {
Some(value)
}
} else {
None
}
} else {
None
}
}
///|
fn add_bs_set_border_at(
node : Attrs,
prop : String,
rank : Int,
value : String,
) -> Unit {
let border_nodes = if node.get_strings(prop) is Some(border_nodes) {
border_nodes
} else {
[]
}
add_bs_ensure_index(border_nodes, rank)
border_nodes[rank] = value
node.set_strings(prop, border_nodes)
}
///|
fn add_bs_ensure_index(values : Array[String], idx : Int) -> Unit {
while values.length() <= idx {
values.push("")
}
}