@@ -73,10 +73,22 @@ const STATE_HEADER_HEIGHT : Double = 26.0
7373const STATE_REGION_GAP : Double = 18.0
7474
7575///|
76- const STATE_NODE_MIN_WIDTH : Double = 72 .0
76+ const STATE_EMPTY_NODE_MIN_WIDTH : Double = 50 .0
7777
7878///|
79- const STATE_NODE_MIN_HEIGHT : Double = 46.0
79+ const STATE_EMPTY_NODE_MIN_HEIGHT : Double = 40.0
80+
81+ ///|
82+ const STATE_COMPARTMENT_MIN_WIDTH : Double = 50.0
83+
84+ ///|
85+ const STATE_COMPARTMENT_MIN_HEIGHT : Double = 50.0
86+
87+ ///|
88+ const STATE_EMPTY_NODE_PADDING : Double = 10.0
89+
90+ ///|
91+ const STATE_COMPARTMENT_PADDING : Double = 20.0
8092
8193///|
8294const STATE_SYNC_WIDTH : Double = 96.0
@@ -356,24 +368,35 @@ fn state_note_size(
356368///|
357369fn StateNode ::leaf_size(
358370 self : StateNode ,
359- metrics : @metrics.FontMetrics ,
371+ name_metrics : @metrics.FontMetrics ,
372+ description_metrics : @metrics.FontMetrics ,
373+ hide_empty_description : Bool ,
360374) -> (Double , Double ) {
361375 match self.kind {
362376 Initial | Final | History | DeepHistory | Choice =>
363377 (STATE_TERMINAL_SIZE , STATE_TERMINAL_SIZE )
364378 Synchronization => (STATE_SYNC_WIDTH , STATE_SYNC_HEIGHT )
365379 Normal => {
366- let description = self.description.unwrap_or("")
367- let text = if description.length() == 0 {
368- self.display
380+ let name = state_text_size(self.display, name_metrics)
381+ if !self.has_description() && hide_empty_description {
382+ (
383+ (name.0 + STATE_EMPTY_NODE_PADDING ).max(STATE_EMPTY_NODE_MIN_WIDTH ),
384+ (name.1 + STATE_EMPTY_NODE_PADDING ).max(STATE_EMPTY_NODE_MIN_HEIGHT ),
385+ )
369386 } else {
370- self.display + "\n" + description
387+ let description = match self.description {
388+ Some (text) => state_text_size(text, description_metrics)
389+ None => (0.0, 0.0)
390+ }
391+ (
392+ (name.0.max(description.0) + STATE_COMPARTMENT_PADDING ).max(
393+ STATE_COMPARTMENT_MIN_WIDTH ,
394+ ),
395+ (name.1 + description.1 + STATE_COMPARTMENT_PADDING ).max(
396+ STATE_COMPARTMENT_MIN_HEIGHT ,
397+ ),
398+ )
371399 }
372- let (width, height) = state_text_size(text, metrics)
373- (
374- (width + 28.0).max(STATE_NODE_MIN_WIDTH ),
375- (height + 20.0).max(STATE_NODE_MIN_HEIGHT ),
376- )
377400 }
378401 }
379402}
@@ -382,26 +405,30 @@ fn StateNode::leaf_size(
382405fn StateDiagram ::composite_fragment(
383406 self : StateDiagram ,
384407 state : StateNode ,
385- metrics : @metrics.FontMetrics ,
408+ name_metrics : @metrics.FontMetrics ,
409+ description_metrics : @metrics.FontMetrics ,
386410) -> StateFragment? raise @dot_layout.DotLayoutError {
387411 guard self.has_children(state.code) else { return None }
388- Some (self.layout_composite_state(state, metrics ))
412+ Some (self.layout_composite_state(state, name_metrics, description_metrics ))
389413}
390414
391415///|
392416fn StateDiagram ::visible_nodes_for_scope(
393417 self : StateDiagram ,
394418 scope : String? ,
395419 region_index : Int ,
396- metrics : @metrics.FontMetrics ,
420+ name_metrics : @metrics.FontMetrics ,
421+ description_metrics : @metrics.FontMetrics ,
397422) -> Array [StateVisibleNode ] raise @dot_layout.DotLayoutError {
398423 let output : Array [StateVisibleNode ] = []
399424 for state in self.states {
400425 guard state.parent == scope else { continue }
401426 guard region_index < 0 || state.region_index == region_index else {
402427 continue
403428 }
404- let child = self.composite_fragment(state, metrics)
429+ let child = self.composite_fragment(
430+ state, name_metrics, description_metrics,
431+ )
405432 output.push({ state, child })
406433 }
407434 output
@@ -433,9 +460,12 @@ fn StateDiagram::layout_scope(
433460 self : StateDiagram ,
434461 scope : String? ,
435462 region_index : Int ,
436- metrics : @metrics.FontMetrics ,
463+ name_metrics : @metrics.FontMetrics ,
464+ description_metrics : @metrics.FontMetrics ,
437465) -> StateFragment raise @dot_layout.DotLayoutError {
438- let visible_nodes = self.visible_nodes_for_scope(scope, region_index, metrics)
466+ let visible_nodes = self.visible_nodes_for_scope(
467+ scope, region_index, name_metrics, description_metrics,
468+ )
439469 let graph = @graphviz.new_directed_graph("state", self.style)
440470 let node_names : Map [String , String ] = Map ([] )
441471 for index, visible in visible_nodes {
@@ -446,11 +476,20 @@ fn StateDiagram::layout_scope(
446476 Some (child) =>
447477 (
448478 (child.width + STATE_INTERNAL_PADDING * 2.0).max(
449- visible.state.leaf_size(metrics).0,
479+ visible.state.leaf_size(
480+ name_metrics,
481+ description_metrics,
482+ self.hide_empty_description(),
483+ ).0,
450484 ),
451485 child.height + STATE_HEADER_HEIGHT + STATE_INTERNAL_PADDING ,
452486 )
453- None => visible.state.leaf_size(metrics)
487+ None =>
488+ visible.state.leaf_size(
489+ name_metrics,
490+ description_metrics,
491+ self.hide_empty_description(),
492+ )
454493 }
455494 @graphviz.set_fixed_node_size(node, width, height)
456495 }
@@ -492,7 +531,7 @@ fn StateDiagram::layout_scope(
492531 let name = @graphviz.graphviz_note_name(note_index)
493532 note_names[name] = note_index
494533 let node = graph.node(name)
495- let (width, height) = state_note_size(note, metrics )
534+ let (width, height) = state_note_size(note, name_metrics )
496535 @graphviz.set_fixed_node_size(node, width, height, shape="note")
497536 match self.note_anchor(note, scope) {
498537 Some (anchor) =>
@@ -647,15 +686,28 @@ fn stack_region_fragments(
647686fn StateDiagram ::layout_composite_state(
648687 self : StateDiagram ,
649688 state : StateNode ,
650- metrics : @metrics.FontMetrics ,
689+ name_metrics : @metrics.FontMetrics ,
690+ description_metrics : @metrics.FontMetrics ,
651691) -> StateFragment raise @dot_layout.DotLayoutError {
652692 let regions = self.regions_for(state.code)
653693 if regions.is_empty() {
654- return self.layout_scope(Some (state.code), -1, metrics)
694+ return self.layout_scope(
695+ Some (state.code),
696+ -1,
697+ name_metrics,
698+ description_metrics,
699+ )
655700 }
656701 let fragments : Array [StateFragment ] = []
657702 for region in regions {
658- fragments.push(self.layout_scope(Some (state.code), region.index, metrics))
703+ fragments.push(
704+ self.layout_scope(
705+ Some (state.code),
706+ region.index,
707+ name_metrics,
708+ description_metrics,
709+ ),
710+ )
659711 }
660712 stack_region_fragments(state.code, regions, fragments)
661713}
@@ -664,8 +716,9 @@ fn StateDiagram::layout_composite_state(
664716pub fn StateDiagram ::layout(
665717 self : StateDiagram ,
666718) -> StateLayout raise @dot_layout.DotLayoutError {
667- let metrics = self.style.font_metrics(font_size=14)
668- let fragment = self.layout_scope(None , -1, metrics)
719+ let name_metrics = state_font_metrics(self.style)
720+ let description_metrics = state_description_font_metrics(self.style)
721+ let fragment = self.layout_scope(None , -1, name_metrics, description_metrics)
669722 {
670723 width: fragment.width + STATE_CANVAS_PADDING * 2.0,
671724 height: fragment.height + STATE_CANVAS_PADDING * 2.0,
0 commit comments