Jelajahi Sumber

Introduce XML rules for "single instance models" (like digital watch). Controller delta can be set in XML.

Joeri Exelmans 5 tahun lalu
induk
melakukan
47499356c2

+ 567 - 0
examples/digitalwatch/model_digitalwatch.svg

@@ -0,0 +1,567 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!-- Generated by graphviz version 2.40.1 (20161225.0304)
+ -->
+<!-- Title: state transitions Pages: 1 -->
+<svg width="4135pt" height="752pt"
+ viewBox="0.00 0.00 4135.00 752.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 748)">
+<title>state transitions</title>
+<polygon fill="#ffffff" stroke="transparent" points="-4,4 -4,-748 4131,-748 4131,4 -4,4"/>
+<g id="clust1" class="cluster">
+<title>cluster__P</title>
+<path fill="none" stroke="#000000" stroke-width="2" d="M20,-8C20,-8 4107,-8 4107,-8 4113,-8 4119,-14 4119,-20 4119,-20 4119,-693 4119,-693 4119,-699 4113,-705 4107,-705 4107,-705 20,-705 20,-705 14,-705 8,-699 8,-693 8,-693 8,-20 8,-20 8,-14 14,-8 20,-8"/>
+<text text-anchor="start" x="2059.4986" y="-686.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">P</text>
+</g>
+<g id="clust2" class="cluster">
+<title>cluster__P_Time</title>
+<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="3839,-291 3839,-589 4111,-589 4111,-291 3839,-291"/>
+<text text-anchor="start" x="3961.6704" y="-570.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Time</text>
+</g>
+<g id="clust3" class="cluster">
+<title>cluster__P_Alarm</title>
+<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="2453,-16 2453,-667 3831,-667 3831,-16 2453,-16"/>
+<text text-anchor="start" x="3126.837" y="-648.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Alarm</text>
+</g>
+<g id="clust4" class="cluster">
+<title>cluster__P_Alarm_Blinking</title>
+<path fill="none" stroke="#000000" stroke-width="2" d="M3617,-24C3617,-24 3811,-24 3811,-24 3817,-24 3823,-30 3823,-36 3823,-36 3823,-617 3823,-617 3823,-623 3817,-629 3811,-629 3811,-629 3617,-629 3617,-629 3611,-629 3605,-623 3605,-617 3605,-617 3605,-36 3605,-36 3605,-30 3611,-24 3617,-24"/>
+<text text-anchor="start" x="3692.9982" y="-610.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Blinking</text>
+<text text-anchor="start" x="3658" y="-590.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">exit ^out.setAlarm</text>
+<text text-anchor="start" x="3657.834" y="-570.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">exit ^out.unsetIndiglo</text>
+<polygon fill="#000000" stroke="#000000" points="3654,-604 3654,-604 3774,-604 3774,-604 3654,-604"/>
+</g>
+<g id="clust5" class="cluster">
+<title>cluster__P_Display</title>
+<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="962,-16 962,-667 2445,-667 2445,-16 962,-16"/>
+<text text-anchor="start" x="1684.335" y="-648.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Display</text>
+</g>
+<g id="clust6" class="cluster">
+<title>cluster__P_Display_EditingTime</title>
+<path fill="none" stroke="#000000" stroke-width="2" d="M1801,-24C1801,-24 2409,-24 2409,-24 2415,-24 2421,-30 2421,-36 2421,-36 2421,-617 2421,-617 2421,-623 2415,-629 2409,-629 2409,-629 1801,-629 1801,-629 1795,-629 1789,-623 1789,-617 1789,-617 1789,-36 1789,-36 1789,-30 1795,-24 1801,-24"/>
+<text text-anchor="start" x="2073.3326" y="-610.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">EditingTime</text>
+<text text-anchor="start" x="2040.8372" y="-590.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.startSelection</text>
+<text text-anchor="start" x="2041" y="-570.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">exit ^out.stopSelection</text>
+<polygon fill="#000000" stroke="#000000" points="2037,-604 2037,-604 2173,-604 2173,-604 2037,-604"/>
+</g>
+<g id="clust7" class="cluster">
+<title>cluster__P_Chrono</title>
+<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="308,-291 308,-589 954,-589 954,-291 308,-291"/>
+<text text-anchor="start" x="611.8296" y="-570.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Chrono</text>
+</g>
+<g id="clust8" class="cluster">
+<title>cluster__P_Indiglo</title>
+<polygon fill="none" stroke="#000000" stroke-dasharray="5,2" points="24,-160 24,-589 300,-589 300,-160 24,-160"/>
+<text text-anchor="start" x="144.8282" y="-570.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Indiglo</text>
+</g>
+<!-- __initial -->
+<g id="node1" class="node">
+<title>__initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="16" cy="-738.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P -->
+<!-- __initial&#45;&gt;_P -->
+<g id="edge1" class="edge">
+<title>__initial&#45;&gt;_P</title>
+<path fill="none" stroke="#000000" d="M16,-732.932C16,-728.8364 16,-722.6612 16,-715.0133"/>
+<polygon fill="#000000" stroke="#000000" points="19.5001,-714.995 16,-704.9951 12.5001,-714.9951 19.5001,-714.995"/>
+<text text-anchor="middle" x="17.3895" y="-716" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Time -->
+<!-- _P_Time_initial -->
+<g id="node4" class="node">
+<title>_P_Time_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="3886" cy="-545.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Time_Increasing -->
+<g id="node6" class="node">
+<title>_P_Time_Increasing</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="3924.5,-458 3847.5,-458 3847.5,-422 3924.5,-422 3924.5,-458"/>
+<text text-anchor="start" x="3858.8268" y="-436.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Increasing</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M3859.8333,-423C3859.8333,-423 3912.1667,-423 3912.1667,-423 3917.8333,-423 3923.5,-428.6667 3923.5,-434.3333 3923.5,-434.3333 3923.5,-445.6667 3923.5,-445.6667 3923.5,-451.3333 3917.8333,-457 3912.1667,-457 3912.1667,-457 3859.8333,-457 3859.8333,-457 3854.1667,-457 3848.5,-451.3333 3848.5,-445.6667 3848.5,-445.6667 3848.5,-434.3333 3848.5,-434.3333 3848.5,-428.6667 3854.1667,-423 3859.8333,-423"/>
+</g>
+<!-- _P_Time_initial&#45;&gt;_P_Time_Increasing -->
+<g id="edge2" class="edge">
+<title>_P_Time_initial&#45;&gt;_P_Time_Increasing</title>
+<path fill="none" stroke="#000000" d="M3886,-539.8288C3886,-535.1736 3886,-528.4097 3886,-522.5 3886,-522.5 3886,-522.5 3886,-475.5 3886,-473.1079 3886,-470.6252 3886,-468.1342"/>
+<polygon fill="#000000" stroke="#000000" points="3889.5001,-468.0597 3886,-458.0598 3882.5001,-468.0598 3889.5001,-468.0597"/>
+<text text-anchor="middle" x="3887.3895" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Time_Editing -->
+<g id="node5" class="node">
+<title>_P_Time_Editing</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="3954,-335 3896,-335 3896,-299 3954,-299 3954,-335"/>
+<text text-anchor="start" x="3906.6622" y="-313.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Editing</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M3908.3333,-300C3908.3333,-300 3941.6667,-300 3941.6667,-300 3947.3333,-300 3953,-305.6667 3953,-311.3333 3953,-311.3333 3953,-322.6667 3953,-322.6667 3953,-328.3333 3947.3333,-334 3941.6667,-334 3941.6667,-334 3908.3333,-334 3908.3333,-334 3902.6667,-334 3897,-328.3333 3897,-322.6667 3897,-322.6667 3897,-311.3333 3897,-311.3333 3897,-305.6667 3902.6667,-300 3908.3333,-300"/>
+</g>
+<!-- _P_Time_Editing&#45;&gt;_P_Time_Increasing -->
+<g id="edge3" class="edge">
+<title>_P_Time_Editing&#45;&gt;_P_Time_Increasing</title>
+<path fill="none" stroke="#000000" d="M3895.9709,-329.7903C3885.8623,-336.3421 3877,-345.5063 3877,-357.5 3877,-404.5 3877,-404.5 3877,-404.5 3877,-406.9141 3877.198,-409.393 3877.5352,-411.8645"/>
+<polygon fill="#000000" stroke="#000000" points="3874.1322,-412.6943 3879.555,-421.7962 3880.9918,-411.2992 3874.1322,-412.6943"/>
+<text text-anchor="start" x="3877" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">edit_done &#160;&#160;</text>
+</g>
+<!-- _P_Time_Increasing&#45;&gt;_P_Time_Editing -->
+<g id="edge5" class="edge">
+<title>_P_Time_Increasing&#45;&gt;_P_Time_Editing</title>
+<path fill="none" stroke="#000000" d="M3924.6661,-431.4317C3947.9017,-425.1242 3973,-415.7153 3973,-404.5 3973,-404.5 3973,-404.5 3973,-357.5 3973,-348.8795 3968.4217,-341.7208 3962.0931,-335.9432"/>
+<polygon fill="#000000" stroke="#000000" points="3964.1023,-333.0738 3954.0291,-329.7903 3959.8561,-338.6388 3964.1023,-333.0738"/>
+<text text-anchor="start" x="3973" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">time_edit &#160;&#160;</text>
+</g>
+<!-- _P_Time_Increasing&#45;&gt;_P_Time_Increasing -->
+<g id="edge4" class="edge">
+<title>_P_Time_Increasing&#45;&gt;_P_Time_Increasing</title>
+<path fill="none" stroke="#000000" d="M3924.6945,-444.8723C3936.8838,-444.7979 3946.5,-443.1738 3946.5,-440 3946.5,-437.7684 3941.7459,-436.303 3934.686,-435.6037"/>
+<polygon fill="#000000" stroke="#000000" points="3934.8497,-432.1076 3924.6945,-435.1277 3934.5166,-439.0997 3934.8497,-432.1076"/>
+<text text-anchor="start" x="3946.5" y="-437" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(1 s)^out.increaseTimeByOne &#160;&#160;</text>
+</g>
+<!-- _P_Alarm -->
+<!-- _P_Alarm_initial -->
+<g id="node8" class="node">
+<title>_P_Alarm_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="2490" cy="-545.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Alarm_Off -->
+<g id="node10" class="node">
+<title>_P_Alarm_Off</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="3252,-458 3196,-458 3196,-422 3252,-422 3252,-458"/>
+<text text-anchor="start" x="3215.9978" y="-436.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Off</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M3208.3333,-423C3208.3333,-423 3239.6667,-423 3239.6667,-423 3245.3333,-423 3251,-428.6667 3251,-434.3333 3251,-434.3333 3251,-445.6667 3251,-445.6667 3251,-451.3333 3245.3333,-457 3239.6667,-457 3239.6667,-457 3208.3333,-457 3208.3333,-457 3202.6667,-457 3197,-451.3333 3197,-445.6667 3197,-445.6667 3197,-434.3333 3197,-434.3333 3197,-428.6667 3202.6667,-423 3208.3333,-423"/>
+</g>
+<!-- _P_Alarm_initial&#45;&gt;_P_Alarm_Off -->
+<g id="edge6" class="edge">
+<title>_P_Alarm_initial&#45;&gt;_P_Alarm_Off</title>
+<path fill="none" stroke="#000000" d="M2490,-539.8288C2490,-535.1736 2490,-528.4097 2490,-522.5 2490,-522.5 2490,-522.5 2490,-475.5 2490,-457.9212 3034.3419,-444.2918 3185.4861,-440.8463"/>
+<polygon fill="#000000" stroke="#000000" points="3185.7578,-444.3411 3195.6761,-440.6159 3185.5995,-437.3429 3185.7578,-444.3411"/>
+<text text-anchor="middle" x="2491.3895" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Alarm_On -->
+<g id="node9" class="node">
+<title>_P_Alarm_On</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="2586.5,-340 2461.5,-340 2461.5,-294 2586.5,-294 2586.5,-340"/>
+<text text-anchor="start" x="2516.4972" y="-323.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">On</text>
+<text text-anchor="start" x="2467.6776" y="-303.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.checkTime</text>
+<polygon fill="#000000" stroke="#000000" points="2462,-317 2462,-317 2587,-317 2587,-317 2462,-317"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M2474.5,-295C2474.5,-295 2573.5,-295 2573.5,-295 2579.5,-295 2585.5,-301 2585.5,-307 2585.5,-307 2585.5,-327 2585.5,-327 2585.5,-333 2579.5,-339 2573.5,-339 2573.5,-339 2474.5,-339 2474.5,-339 2468.5,-339 2462.5,-333 2462.5,-327 2462.5,-327 2462.5,-307 2462.5,-307 2462.5,-301 2468.5,-295 2474.5,-295"/>
+</g>
+<!-- _P_Alarm_On&#45;&gt;_P_Alarm_On -->
+<g id="edge15" class="edge">
+<title>_P_Alarm_On&#45;&gt;_P_Alarm_On</title>
+<path fill="none" stroke="#000000" d="M2586.6458,-322.4104C2599.3807,-321.8211 2608.5,-320.0176 2608.5,-317 2608.5,-314.8783 2603.9916,-313.3568 2596.8879,-312.4355"/>
+<polygon fill="#000000" stroke="#000000" points="2596.9,-308.9247 2586.6458,-311.5896 2596.3238,-315.9009 2596.9,-308.9247"/>
+<text text-anchor="start" x="2608.5" y="-314" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(1 s) &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_On&#45;&gt;_P_Alarm_Off -->
+<g id="edge14" class="edge">
+<title>_P_Alarm_On&#45;&gt;_P_Alarm_Off</title>
+<path fill="none" stroke="#000000" d="M2586.5565,-318.4052C2730.7111,-322.0571 3074,-333.2946 3074,-357.5 3074,-404.5 3074,-404.5 3074,-404.5 3074,-427.4168 3141.1385,-435.5593 3185.5813,-438.4389"/>
+<polygon fill="#000000" stroke="#000000" points="3185.5991,-441.9458 3195.7861,-439.0349 3186.0072,-434.9578 3185.5991,-441.9458"/>
+<text text-anchor="start" x="3074" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftPressed [INSTATE([&quot;/P/Display/TimeUpdate&quot;]) or INSTATE([&quot;/P/Display/WaitingForAlarm&quot;])]^out.setAlarm &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking -->
+<!-- _P_Alarm_On&#45;&gt;_P_Alarm_Blinking -->
+<g id="edge16" class="edge">
+<title>_P_Alarm_On&#45;&gt;_P_Alarm_Blinking</title>
+<path fill="none" stroke="#000000" d="M2501.0166,-340.046C2492.706,-349.9465 2484.3118,-362.182 2480,-375 2474.7283,-390.6714 2486.9964,-398.0519 2502,-405 2797.6519,-541.9146 2899.7217,-500.3893 3224,-532 3243.7539,-533.9256 3541.9005,-530.6383 3603.1745,-542.3114"/>
+<polygon fill="#000000" stroke="#000000" points="3594.5552,-541.5436 3605,-543.3211 3597.9433,-535.4181 3594.5552,-541.5436"/>
+<text text-anchor="start" x="2628" y="-437" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">alarmStart &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Off&#45;&gt;_P_Alarm_On -->
+<g id="edge17" class="edge">
+<title>_P_Alarm_Off&#45;&gt;_P_Alarm_On</title>
+<path fill="none" stroke="#000000" d="M3195.8928,-439.3563C3063.3298,-436.2304 2507,-422.0653 2507,-404.5 2507,-404.5 2507,-404.5 2507,-357.5 2507,-355.0551 2507.2667,-352.5873 2507.7332,-350.1407"/>
+<polygon fill="#000000" stroke="#000000" points="2511.1589,-350.8958 2510.6053,-340.3155 2504.44,-348.9318 2511.1589,-350.8958"/>
+<text text-anchor="start" x="2507" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftPressed [INSTATE([&quot;/P/Display/TimeUpdate&quot;]) or INSTATE([&quot;/P/Display/WaitingForAlarm&quot;])]^out.setAlarm &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking&#45;&gt;_P_Alarm_Off -->
+<g id="edge10" class="edge">
+<title>_P_Alarm_Blinking&#45;&gt;_P_Alarm_Off</title>
+<path fill="none" stroke="#000000" d="M3605.0038,-538.9424C3571.0212,-533.0836 3357.9135,-532.7603 3344,-532 3317.2897,-530.5404 3224,-549.2501 3224,-522.5 3224,-522.5 3224,-522.5 3224,-475.5 3224,-473.1079 3224,-470.6252 3224,-468.1342"/>
+<polygon fill="#000000" stroke="#000000" points="3227.5001,-468.0597 3224,-458.0598 3220.5001,-468.0598 3227.5001,-468.0597"/>
+<text text-anchor="start" x="3224" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topRightPressed &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking&#45;&gt;_P_Alarm_Off -->
+<g id="edge11" class="edge">
+<title>_P_Alarm_Blinking&#45;&gt;_P_Alarm_Off</title>
+<path fill="none" stroke="#000000" d="M3605.002,-538.5972C3580.29,-532.3845 3479.0478,-533.0419 3464,-532 3438.6396,-530.2441 3350,-547.9211 3350,-522.5 3350,-522.5 3350,-522.5 3350,-475.5 3350,-457.0634 3299.3897,-447.7368 3262.32,-443.3783"/>
+<polygon fill="#000000" stroke="#000000" points="3262.5988,-439.888 3252.2769,-442.2773 3261.8359,-446.8463 3262.5988,-439.888"/>
+<text text-anchor="start" x="3350" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topLeftPressed &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking&#45;&gt;_P_Alarm_Off -->
+<g id="edge12" class="edge">
+<title>_P_Alarm_Blinking&#45;&gt;_P_Alarm_Off</title>
+<path fill="none" stroke="#000000" d="M3605.0007,-538.1702C3572.5775,-526.6307 3470,-552.2684 3470,-522.5 3470,-522.5 3470,-522.5 3470,-475.5 3470,-454.7729 3331.4279,-445.1614 3262.2898,-441.6558"/>
+<polygon fill="#000000" stroke="#000000" points="3262.3783,-438.1561 3252.2193,-441.1635 3262.0365,-445.1477 3262.3783,-438.1561"/>
+<text text-anchor="start" x="3470" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightPressed &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking&#45;&gt;_P_Alarm_Off -->
+<g id="edge13" class="edge">
+<title>_P_Alarm_Blinking&#45;&gt;_P_Alarm_Off</title>
+<path fill="none" stroke="#000000" d="M3605.0032,-470.1267C3561.3042,-455.4953 3350.153,-445.2252 3262.3843,-441.521"/>
+<polygon fill="#000000" stroke="#000000" points="3262.4261,-438.0198 3252.2893,-441.1011 3262.1351,-445.0138 3262.4261,-438.0198"/>
+<text text-anchor="start" x="3613" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftPressed &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking_initial -->
+<g id="node12" class="node">
+<title>_P_Alarm_Blinking_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="3737" cy="-545.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Alarm_Blinking_On -->
+<g id="node14" class="node">
+<title>_P_Alarm_Blinking_On</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="3796,-340 3678,-340 3678,-294 3796,-294 3796,-340"/>
+<text text-anchor="start" x="3728.9972" y="-323.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">On</text>
+<text text-anchor="start" x="3683.5034" y="-303.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.setIndiglo</text>
+<polygon fill="#000000" stroke="#000000" points="3678,-317 3678,-317 3796,-317 3796,-317 3678,-317"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M3691,-295C3691,-295 3783,-295 3783,-295 3789,-295 3795,-301 3795,-307 3795,-307 3795,-327 3795,-327 3795,-333 3789,-339 3783,-339 3783,-339 3691,-339 3691,-339 3685,-339 3679,-333 3679,-327 3679,-327 3679,-307 3679,-307 3679,-301 3685,-295 3691,-295"/>
+</g>
+<!-- _P_Alarm_Blinking_initial&#45;&gt;_P_Alarm_Blinking_On -->
+<g id="edge7" class="edge">
+<title>_P_Alarm_Blinking_initial&#45;&gt;_P_Alarm_Blinking_On</title>
+<path fill="none" stroke="#000000" d="M3737,-539.8288C3737,-535.1736 3737,-528.4097 3737,-522.5 3737,-522.5 3737,-522.5 3737,-357.5 3737,-355.127 3737,-352.6757 3737,-350.2081"/>
+<polygon fill="#000000" stroke="#000000" points="3740.5001,-350.1306 3737,-340.1306 3733.5001,-350.1306 3740.5001,-350.1306"/>
+<text text-anchor="middle" x="3738.3895" y="-437" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Alarm_Blinking_Off -->
+<g id="node13" class="node">
+<title>_P_Alarm_Blinking_Off</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="3779,-78 3647,-78 3647,-32 3779,-32 3779,-78"/>
+<text text-anchor="start" x="3704.9978" y="-61.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Off</text>
+<text text-anchor="start" x="3652.8326" y="-41.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.unsetIndiglo</text>
+<polygon fill="#000000" stroke="#000000" points="3647,-55 3647,-55 3779,-55 3779,-55 3647,-55"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M3660,-33C3660,-33 3766,-33 3766,-33 3772,-33 3778,-39 3778,-45 3778,-45 3778,-65 3778,-65 3778,-71 3772,-77 3766,-77 3766,-77 3660,-77 3660,-77 3654,-77 3648,-71 3648,-65 3648,-65 3648,-45 3648,-45 3648,-39 3654,-33 3660,-33"/>
+</g>
+<!-- _P_Alarm_Blinking_Off&#45;&gt;_P_Alarm_Blinking_On -->
+<g id="edge8" class="edge">
+<title>_P_Alarm_Blinking_Off&#45;&gt;_P_Alarm_Blinking_On</title>
+<path fill="none" stroke="#000000" d="M3646.8465,-72.958C3639.7238,-78.5531 3635,-85.8873 3635,-95.5 3635,-273.5 3635,-273.5 3635,-273.5 3635,-274.1287 3651.995,-281.4919 3672.1106,-289.9871"/>
+<polygon fill="#000000" stroke="#000000" points="3670.9481,-293.2952 3681.5227,-293.9499 3673.6644,-286.8437 3670.9481,-293.2952"/>
+<text text-anchor="start" x="3635" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(500 ms) &#160;&#160;</text>
+</g>
+<!-- _P_Alarm_Blinking_On&#45;&gt;_P_Alarm_Blinking_Off -->
+<g id="edge9" class="edge">
+<title>_P_Alarm_Blinking_On&#45;&gt;_P_Alarm_Blinking_Off</title>
+<path fill="none" stroke="#000000" d="M3744.3726,-293.7454C3745.8715,-287.26 3747,-280.1642 3747,-273.5 3747,-273.5 3747,-273.5 3747,-95.5 3747,-92.6713 3746.5074,-89.9368 3745.6409,-87.3148"/>
+<polygon fill="#000000" stroke="#000000" points="3748.7316,-85.671 3741.0777,-78.3452 3742.4926,-88.8451 3748.7316,-85.671"/>
+<text text-anchor="start" x="3747" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(500 ms) &#160;&#160;</text>
+</g>
+<!-- _P_Display -->
+<!-- _P_Display_initial -->
+<g id="node16" class="node">
+<title>_P_Display_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="1473" cy="-317" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Display_TimeUpdate -->
+<g id="node20" class="node">
+<title>_P_Display_TimeUpdate</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="1558,-209 1388,-209 1388,-163 1558,-163 1558,-209"/>
+<text text-anchor="start" x="1440.33" y="-192.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">TimeUpdate</text>
+<text text-anchor="start" x="1393.515" y="-172.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.refreshTimeDisplay</text>
+<polygon fill="#000000" stroke="#000000" points="1388,-186 1388,-186 1558,-186 1558,-186 1388,-186"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M1401,-164C1401,-164 1545,-164 1545,-164 1551,-164 1557,-170 1557,-176 1557,-176 1557,-196 1557,-196 1557,-202 1551,-208 1545,-208 1545,-208 1401,-208 1401,-208 1395,-208 1389,-202 1389,-196 1389,-196 1389,-176 1389,-176 1389,-170 1395,-164 1401,-164"/>
+</g>
+<!-- _P_Display_initial&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge18" class="edge">
+<title>_P_Display_initial&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M1473,-311.369C1473,-303.077 1473,-287.0938 1473,-273.5 1473,-273.5 1473,-273.5 1473,-226.5 1473,-224.127 1473,-221.6757 1473,-219.2081"/>
+<polygon fill="#000000" stroke="#000000" points="1476.5001,-219.1306 1473,-209.1306 1469.5001,-219.1306 1476.5001,-219.1306"/>
+<text text-anchor="middle" x="1474.3895" y="-247" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Display_WaitingForAlarm -->
+<g id="node17" class="node">
+<title>_P_Display_WaitingForAlarm</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="1145.5,-78 970.5,-78 970.5,-32 1145.5,-32 1145.5,-78"/>
+<text text-anchor="start" x="1013.839" y="-61.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">WaitingForAlarm</text>
+<text text-anchor="start" x="976.6816" y="-41.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.refreshAlarmDisplay</text>
+<polygon fill="#000000" stroke="#000000" points="971,-55 971,-55 1146,-55 1146,-55 971,-55"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M983.5,-33C983.5,-33 1132.5,-33 1132.5,-33 1138.5,-33 1144.5,-39 1144.5,-45 1144.5,-45 1144.5,-65 1144.5,-65 1144.5,-71 1138.5,-77 1132.5,-77 1132.5,-77 983.5,-77 983.5,-77 977.5,-77 971.5,-71 971.5,-65 971.5,-65 971.5,-45 971.5,-45 971.5,-39 977.5,-33 983.5,-33"/>
+</g>
+<!-- _P_Display_WaitingForAlarm&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge20" class="edge">
+<title>_P_Display_WaitingForAlarm&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M1134.759,-78.2221C1144.9718,-83.4343 1152,-89.2806 1152,-95.5 1152,-142.5 1152,-142.5 1152,-142.5 1152,-165.4933 1283.0022,-176.8615 1377.6297,-182.0739"/>
+<polygon fill="#000000" stroke="#000000" points="1377.6478,-185.5798 1387.8207,-182.6194 1378.0221,-178.5898 1377.6478,-185.5798"/>
+<text text-anchor="start" x="1152" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftReleased &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime -->
+<!-- _P_Display_WaitingForAlarm&#45;&gt;_P_Display_EditingTime -->
+<g id="edge19" class="edge">
+<title>_P_Display_WaitingForAlarm&#45;&gt;_P_Display_EditingTime</title>
+<path fill="none" stroke="#000000" d="M1016.9148,-78.1274C1005.1915,-87.2213 994.1907,-98.9021 989,-113 964.3492,-179.9519 992,-202.1542 992,-273.5 992,-522.5 992,-522.5 992,-522.5 992,-532.2224 1529.5519,-540.5797 1778.8053,-543.9322"/>
+<polygon fill="#000000" stroke="#000000" points="1778.9559,-547.4344 1789.0019,-544.0687 1779.0497,-540.4351 1778.9559,-547.4344"/>
+<text text-anchor="start" x="992" y="-314" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(1500 ms)^alarm_edit &#160;&#160;</text>
+</g>
+<!-- _P_Display_ChronoUpdate -->
+<g id="node18" class="node">
+<title>_P_Display_ChronoUpdate</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="1377,-73 1277,-73 1277,-37 1377,-37 1377,-73"/>
+<text text-anchor="start" x="1287.9892" y="-51.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">ChronoUpdate</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M1289.3333,-38C1289.3333,-38 1364.6667,-38 1364.6667,-38 1370.3333,-38 1376,-43.6667 1376,-49.3333 1376,-49.3333 1376,-60.6667 1376,-60.6667 1376,-66.3333 1370.3333,-72 1364.6667,-72 1364.6667,-72 1289.3333,-72 1289.3333,-72 1283.6667,-72 1278,-66.3333 1278,-60.6667 1278,-60.6667 1278,-49.3333 1278,-49.3333 1278,-43.6667 1283.6667,-38 1289.3333,-38"/>
+</g>
+<!-- _P_Display_ChronoUpdate&#45;&gt;_P_Display_ChronoUpdate -->
+<g id="edge22" class="edge">
+<title>_P_Display_ChronoUpdate&#45;&gt;_P_Display_ChronoUpdate</title>
+<path fill="none" stroke="#000000" d="M1377.1354,-60.5478C1389.6477,-60.1598 1399,-58.3105 1399,-55 1399,-52.6723 1394.3764,-51.067 1387.2816,-50.1841"/>
+<polygon fill="#000000" stroke="#000000" points="1387.3613,-46.6809 1377.1354,-49.4522 1386.8576,-53.6627 1387.3613,-46.6809"/>
+<text text-anchor="start" x="1399" y="-52" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(30 ms)^out.refreshChronoDisplay &#160;&#160;</text>
+</g>
+<!-- _P_Display_ChronoUpdate&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge21" class="edge">
+<title>_P_Display_ChronoUpdate&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M1377.1042,-69.6059C1396.4436,-76.7744 1414,-85.9202 1414,-95.5 1414,-142.5 1414,-142.5 1414,-142.5 1414,-146.8845 1415.0686,-150.8768 1416.9183,-154.503"/>
+<polygon fill="#000000" stroke="#000000" points="1414.2367,-156.7657 1422.9608,-162.7775 1419.8898,-152.6375 1414.2367,-156.7657"/>
+<text text-anchor="start" x="1414" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topLeftPressed &#160;&#160;</text>
+</g>
+<!-- _P_Display_WaitingToEdit -->
+<g id="node19" class="node">
+<title>_P_Display_WaitingToEdit</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="1725,-73 1629,-73 1629,-37 1725,-37 1725,-73"/>
+<text text-anchor="start" x="1639.6638" y="-51.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">WaitingToEdit</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M1641.3333,-38C1641.3333,-38 1712.6667,-38 1712.6667,-38 1718.3333,-38 1724,-43.6667 1724,-49.3333 1724,-49.3333 1724,-60.6667 1724,-60.6667 1724,-66.3333 1718.3333,-72 1712.6667,-72 1712.6667,-72 1641.3333,-72 1641.3333,-72 1635.6667,-72 1630,-66.3333 1630,-60.6667 1630,-60.6667 1630,-49.3333 1630,-49.3333 1630,-43.6667 1635.6667,-38 1641.3333,-38"/>
+</g>
+<!-- _P_Display_WaitingToEdit&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge32" class="edge">
+<title>_P_Display_WaitingToEdit&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M1677,-73.1447C1677,-80.1323 1677,-88.1875 1677,-95.5 1677,-142.5 1677,-142.5 1677,-142.5 1677,-154.6236 1621.1775,-165.9667 1567.9347,-174.0283"/>
+<polygon fill="#000000" stroke="#000000" points="1567.4161,-170.5669 1558.0372,-175.4949 1568.4422,-177.4913 1567.4161,-170.5669"/>
+<text text-anchor="start" x="1677" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightReleased &#160;&#160;</text>
+</g>
+<!-- _P_Display_WaitingToEdit&#45;&gt;_P_Display_EditingTime -->
+<g id="edge31" class="edge">
+<title>_P_Display_WaitingToEdit&#45;&gt;_P_Display_EditingTime</title>
+<path fill="none" stroke="#000000" d="M1725.152,-67.3307C1740.8785,-70.9076 1758.685,-74.4963 1778.8891,-77.0626"/>
+<polygon fill="#000000" stroke="#000000" points="1778.6647,-80.56 1789.0014,-78.2358 1779.4714,-73.6066 1778.6647,-80.56"/>
+<text text-anchor="start" x="2329" y="-314" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(1500 ms)^time_edit &#160;&#160;</text>
+</g>
+<!-- _P_Display_TimeUpdate&#45;&gt;_P_Display_WaitingForAlarm -->
+<g id="edge36" class="edge">
+<title>_P_Display_TimeUpdate&#45;&gt;_P_Display_WaitingForAlarm</title>
+<path fill="none" stroke="#000000" d="M1387.8455,-182.1112C1255.6286,-175.499 1016,-160.9677 1016,-142.5 1016,-142.5 1016,-142.5 1016,-95.5 1016,-92.5624 1016.539,-89.7707 1017.4948,-87.1294"/>
+<polygon fill="#000000" stroke="#000000" points="1020.6545,-88.6536 1022.5625,-78.232 1014.572,-85.1892 1020.6545,-88.6536"/>
+<text text-anchor="start" x="1016" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftPressed &#160;&#160;</text>
+</g>
+<!-- _P_Display_TimeUpdate&#45;&gt;_P_Display_ChronoUpdate -->
+<g id="edge34" class="edge">
+<title>_P_Display_TimeUpdate&#45;&gt;_P_Display_ChronoUpdate</title>
+<path fill="none" stroke="#000000" d="M1387.9559,-180.1576C1341.771,-174.5543 1294,-163.6473 1294,-142.5 1294,-142.5 1294,-142.5 1294,-95.5 1294,-90.5456 1295.5025,-85.8615 1297.8663,-81.558"/>
+<polygon fill="#000000" stroke="#000000" points="1300.7962,-83.477 1303.7226,-73.2943 1295.0849,-79.4295 1300.7962,-83.477"/>
+<text text-anchor="start" x="1294" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topLeftPressed &#160;&#160;</text>
+</g>
+<!-- _P_Display_TimeUpdate&#45;&gt;_P_Display_WaitingToEdit -->
+<g id="edge35" class="edge">
+<title>_P_Display_TimeUpdate&#45;&gt;_P_Display_WaitingToEdit</title>
+<path fill="none" stroke="#000000" d="M1524.9992,-162.8124C1530.4221,-157.2742 1534,-150.5645 1534,-142.5 1534,-142.5 1534,-142.5 1534,-95.5 1534,-93.1684 1579.6107,-80.5527 1619.3138,-70.0127"/>
+<polygon fill="#000000" stroke="#000000" points="1620.2126,-73.3954 1628.9853,-67.4548 1618.4227,-66.6281 1620.2126,-73.3954"/>
+<text text-anchor="start" x="1534" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightPressed &#160;&#160;</text>
+</g>
+<!-- _P_Display_TimeUpdate&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge33" class="edge">
+<title>_P_Display_TimeUpdate&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M1558.1998,-191.1292C1571.1835,-190.3465 1580,-188.6367 1580,-186 1580,-184.1461 1575.6412,-182.7504 1568.5399,-181.813"/>
+<polygon fill="#000000" stroke="#000000" points="1568.4761,-178.2928 1558.1998,-180.8708 1567.8408,-185.2639 1568.4761,-178.2928"/>
+<text text-anchor="start" x="1580" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(1 s) &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_initial -->
+<g id="node22" class="node">
+<title>_P_Display_EditingTime_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="2036" cy="-545.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Display_EditingTime_Waiting -->
+<g id="node25" class="node">
+<title>_P_Display_EditingTime_Waiting</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="2066.5,-335 2005.5,-335 2005.5,-299 2066.5,-299 2066.5,-335"/>
+<text text-anchor="start" x="2016.5002" y="-313.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Waiting</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M2017.8333,-300C2017.8333,-300 2054.1667,-300 2054.1667,-300 2059.8333,-300 2065.5,-305.6667 2065.5,-311.3333 2065.5,-311.3333 2065.5,-322.6667 2065.5,-322.6667 2065.5,-328.3333 2059.8333,-334 2054.1667,-334 2054.1667,-334 2017.8333,-334 2017.8333,-334 2012.1667,-334 2006.5,-328.3333 2006.5,-322.6667 2006.5,-322.6667 2006.5,-311.3333 2006.5,-311.3333 2006.5,-305.6667 2012.1667,-300 2017.8333,-300"/>
+</g>
+<!-- _P_Display_EditingTime_initial&#45;&gt;_P_Display_EditingTime_Waiting -->
+<g id="edge23" class="edge">
+<title>_P_Display_EditingTime_initial&#45;&gt;_P_Display_EditingTime_Waiting</title>
+<path fill="none" stroke="#000000" d="M2036,-539.8288C2036,-535.1736 2036,-528.4097 2036,-522.5 2036,-522.5 2036,-522.5 2036,-357.5 2036,-353.6152 2036,-349.5209 2036,-345.4883"/>
+<polygon fill="#000000" stroke="#000000" points="2039.5001,-345.1447 2036,-335.1447 2032.5001,-345.1448 2039.5001,-345.1447"/>
+<text text-anchor="middle" x="2037.3895" y="-437" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Display_EditingTime_Increasing -->
+<g id="node23" class="node">
+<title>_P_Display_EditingTime_Increasing</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="2294,-78 2132,-78 2132,-32 2294,-32 2294,-78"/>
+<text text-anchor="start" x="2185.3268" y="-61.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Increasing</text>
+<text text-anchor="start" x="2137.8344" y="-41.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">entry ^out.increaseSelection</text>
+<polygon fill="#000000" stroke="#000000" points="2132,-55 2132,-55 2294,-55 2294,-55 2132,-55"/>
+<path fill="none" stroke="#000000" stroke-width="2" d="M2145,-33C2145,-33 2281,-33 2281,-33 2287,-33 2293,-39 2293,-45 2293,-45 2293,-65 2293,-65 2293,-71 2287,-77 2281,-77 2281,-77 2145,-77 2145,-77 2139,-77 2133,-71 2133,-65 2133,-65 2133,-45 2133,-45 2133,-39 2139,-33 2145,-33"/>
+</g>
+<!-- _P_Display_EditingTime_Increasing&#45;&gt;_P_Display_EditingTime_Increasing -->
+<g id="edge24" class="edge">
+<title>_P_Display_EditingTime_Increasing&#45;&gt;_P_Display_EditingTime_Increasing</title>
+<path fill="none" stroke="#000000" d="M2294.1756,-60.1801C2307.1317,-59.422 2316,-57.6953 2316,-55 2316,-53.1049 2311.6156,-51.6886 2304.5087,-50.7512"/>
+<polygon fill="#000000" stroke="#000000" points="2304.4494,-47.2318 2294.1756,-49.8199 2303.821,-54.2035 2304.4494,-47.2318"/>
+<text text-anchor="start" x="2316" y="-52" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(300 ms) &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_Increasing&#45;&gt;_P_Display_EditingTime_Waiting -->
+<g id="edge25" class="edge">
+<title>_P_Display_EditingTime_Increasing&#45;&gt;_P_Display_EditingTime_Waiting</title>
+<path fill="none" stroke="#000000" d="M2294.3588,-76.6148C2306.4772,-82.0922 2315,-88.4503 2315,-95.5 2315,-273.5 2315,-273.5 2315,-273.5 2315,-300.6808 2096.4908,-281.5653 2071,-291 2069.0833,-291.7094 2067.1816,-292.5584 2065.313,-293.5096"/>
+<polygon fill="#000000" stroke="#000000" points="2063.074,-290.7735 2056.3303,-298.9449 2066.6979,-296.7625 2063.074,-290.7735"/>
+<text text-anchor="start" x="2315" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftReleased &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_GoingToNext -->
+<g id="node24" class="node">
+<title>_P_Display_EditingTime_GoingToNext</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="1991,-73 1899,-73 1899,-37 1991,-37 1991,-73"/>
+<text text-anchor="start" x="1909.66" y="-51.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">GoingToNext</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M1911.3333,-38C1911.3333,-38 1978.6667,-38 1978.6667,-38 1984.3333,-38 1990,-43.6667 1990,-49.3333 1990,-49.3333 1990,-60.6667 1990,-60.6667 1990,-66.3333 1984.3333,-72 1978.6667,-72 1978.6667,-72 1911.3333,-72 1911.3333,-72 1905.6667,-72 1900,-66.3333 1900,-60.6667 1900,-60.6667 1900,-49.3333 1900,-49.3333 1900,-43.6667 1905.6667,-38 1911.3333,-38"/>
+</g>
+<!-- _P_Display_EditingTime_GoingToNext&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge27" class="edge">
+<title>_P_Display_EditingTime_GoingToNext&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M1907.6337,-73.0963C1903.4172,-74.8658 1899.1465,-76.5423 1895,-78 1864.7465,-88.6358 1825,-63.4314 1825,-95.5 1825,-142.5 1825,-142.5 1825,-142.5 1825,-155.4612 1672.6969,-170.1926 1568.4557,-178.7574"/>
+<polygon fill="#000000" stroke="#000000" points="1567.8921,-175.2916 1558.2094,-179.5922 1568.4606,-182.2685 1567.8921,-175.2916"/>
+<text text-anchor="start" x="1825" y="-116" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(2 s)^edit_done &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_GoingToNext&#45;&gt;_P_Display_EditingTime_Waiting -->
+<g id="edge26" class="edge">
+<title>_P_Display_EditingTime_GoingToNext&#45;&gt;_P_Display_EditingTime_Waiting</title>
+<path fill="none" stroke="#000000" d="M1947.9636,-73.281C1949.4359,-88.2348 1949.2615,-109.3864 1940,-125 1915.2251,-166.7668 1871.2694,-126.1051 1836.493,-160 1817.3639,-178.6443 1819,-190.788 1819,-217.5 1819,-273.5 1819,-273.5 1819,-273.5 1819,-293.9261 1982.9866,-283.5357 2002,-291 2003.8157,-291.7128 2005.6165,-292.5528 2007.3864,-293.4864"/>
+<polygon fill="#000000" stroke="#000000" points="2005.563,-296.474 2015.9041,-298.7791 2009.2576,-290.5284 2005.563,-296.474"/>
+<text text-anchor="start" x="1836" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightReleased^out.selectNext &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_Waiting&#45;&gt;_P_Display_TimeUpdate -->
+<g id="edge30" class="edge">
+<title>_P_Display_EditingTime_Waiting&#45;&gt;_P_Display_TimeUpdate</title>
+<path fill="none" stroke="#000000" d="M2016.3515,-298.8374C2011.9205,-295.6763 2007.0303,-292.8224 2002,-291 1983.0172,-284.1229 1639,-293.6901 1639,-273.5 1639,-273.5 1639,-273.5 1639,-226.5 1639,-209.4123 1605.382,-199.5023 1568.4036,-193.7702"/>
+<polygon fill="#000000" stroke="#000000" points="1568.8287,-190.2954 1558.4313,-192.3315 1567.829,-197.2237 1568.8287,-190.2954"/>
+<text text-anchor="start" x="1639" y="-247" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(5 s)^edit_done &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_Waiting&#45;&gt;_P_Display_EditingTime_Increasing -->
+<g id="edge28" class="edge">
+<title>_P_Display_EditingTime_Waiting&#45;&gt;_P_Display_EditingTime_Increasing</title>
+<path fill="none" stroke="#000000" d="M2057.2323,-298.7702C2061.5666,-295.7769 2066.2586,-293.0034 2071,-291 2093.3959,-281.537 2179,-297.813 2179,-273.5 2179,-273.5 2179,-273.5 2179,-95.5 2179,-92.6713 2179.4926,-89.9368 2180.3591,-87.3148"/>
+<polygon fill="#000000" stroke="#000000" points="2183.5074,-88.8451 2184.9223,-78.3452 2177.2684,-85.671 2183.5074,-88.8451"/>
+<text text-anchor="start" x="2179" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftPressed &#160;&#160;</text>
+</g>
+<!-- _P_Display_EditingTime_Waiting&#45;&gt;_P_Display_EditingTime_GoingToNext -->
+<g id="edge29" class="edge">
+<title>_P_Display_EditingTime_Waiting&#45;&gt;_P_Display_EditingTime_GoingToNext</title>
+<path fill="none" stroke="#000000" d="M2036,-298.7983C2036,-291.007 2036,-281.8073 2036,-273.5 2036,-273.5 2036,-273.5 2036,-95.5 2036,-86.1063 2019.6101,-77.3914 2000.7417,-70.471"/>
+<polygon fill="#000000" stroke="#000000" points="2001.6279,-67.0744 1991.0332,-67.1225 1999.3455,-73.6919 2001.6279,-67.0744"/>
+<text text-anchor="start" x="2036" y="-183" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightPressed &#160;&#160;</text>
+</g>
+<!-- _P_Chrono -->
+<!-- _P_Chrono_initial -->
+<g id="node27" class="node">
+<title>_P_Chrono_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="446" cy="-545.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Chrono_Stopped -->
+<g id="node29" class="node">
+<title>_P_Chrono_Stopped</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="479,-458 413,-458 413,-422 479,-422 479,-458"/>
+<text text-anchor="start" x="423.6542" y="-436.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Stopped</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M425.3333,-423C425.3333,-423 466.6667,-423 466.6667,-423 472.3333,-423 478,-428.6667 478,-434.3333 478,-434.3333 478,-445.6667 478,-445.6667 478,-451.3333 472.3333,-457 466.6667,-457 466.6667,-457 425.3333,-457 425.3333,-457 419.6667,-457 414,-451.3333 414,-445.6667 414,-445.6667 414,-434.3333 414,-434.3333 414,-428.6667 419.6667,-423 425.3333,-423"/>
+</g>
+<!-- _P_Chrono_initial&#45;&gt;_P_Chrono_Stopped -->
+<g id="edge37" class="edge">
+<title>_P_Chrono_initial&#45;&gt;_P_Chrono_Stopped</title>
+<path fill="none" stroke="#000000" d="M446,-539.8288C446,-535.1736 446,-528.4097 446,-522.5 446,-522.5 446,-522.5 446,-475.5 446,-473.1079 446,-470.6252 446,-468.1342"/>
+<polygon fill="#000000" stroke="#000000" points="449.5001,-468.0597 446,-458.0598 442.5001,-468.0598 449.5001,-468.0597"/>
+<text text-anchor="middle" x="447.3895" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Chrono_Running -->
+<g id="node28" class="node">
+<title>_P_Chrono_Running</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="539,-335 473,-335 473,-299 539,-299 539,-335"/>
+<text text-anchor="start" x="483.6602" y="-313.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Running</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M485.3333,-300C485.3333,-300 526.6667,-300 526.6667,-300 532.3333,-300 538,-305.6667 538,-311.3333 538,-311.3333 538,-322.6667 538,-322.6667 538,-328.3333 532.3333,-334 526.6667,-334 526.6667,-334 485.3333,-334 485.3333,-334 479.6667,-334 474,-328.3333 474,-322.6667 474,-322.6667 474,-311.3333 474,-311.3333 474,-305.6667 479.6667,-300 485.3333,-300"/>
+</g>
+<!-- _P_Chrono_Running&#45;&gt;_P_Chrono_Running -->
+<g id="edge38" class="edge">
+<title>_P_Chrono_Running&#45;&gt;_P_Chrono_Running</title>
+<path fill="none" stroke="#000000" d="M539.0221,-322.6164C551.1032,-322.7686 561,-320.8965 561,-317 561,-314.3212 556.3222,-312.5992 549.4728,-311.834"/>
+<polygon fill="#000000" stroke="#000000" points="549.1636,-308.3175 539.0221,-311.3836 548.8621,-315.311 549.1636,-308.3175"/>
+<text text-anchor="start" x="561" y="-314" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(10 ms)^out.increaseChronoByOne &#160;&#160;</text>
+</g>
+<!-- _P_Chrono_Running&#45;&gt;_P_Chrono_Stopped -->
+<g id="edge39" class="edge">
+<title>_P_Chrono_Running&#45;&gt;_P_Chrono_Stopped</title>
+<path fill="none" stroke="#000000" d="M472.8086,-318.3048C423.8483,-321.1482 338,-330.048 338,-357.5 338,-404.5 338,-404.5 338,-404.5 338,-418.8189 372.6948,-428.3106 402.7553,-433.8471"/>
+<polygon fill="#000000" stroke="#000000" points="402.2642,-437.3141 412.7152,-435.5744 403.4603,-430.4171 402.2642,-437.3141"/>
+<text text-anchor="start" x="338" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightPressed [INSTATE([&quot;/P/Display/ChronoUpdate&quot;])] &#160;&#160;</text>
+</g>
+<!-- _P_Chrono_Stopped&#45;&gt;_P_Chrono_Running -->
+<g id="edge41" class="edge">
+<title>_P_Chrono_Stopped&#45;&gt;_P_Chrono_Running</title>
+<path fill="none" stroke="#000000" d="M479.1095,-437.9698C540.0943,-433.7837 664,-423.0018 664,-404.5 664,-404.5 664,-404.5 664,-357.5 664,-333.7405 596.11,-323.7276 549.3342,-319.6486"/>
+<polygon fill="#000000" stroke="#000000" points="549.3719,-316.1403 539.122,-318.8215 548.8068,-323.1174 549.3719,-316.1403"/>
+<text text-anchor="start" x="664" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomRightPressed [INSTATE([&quot;/P/Display/ChronoUpdate&quot;])] &#160;&#160;</text>
+</g>
+<!-- _P_Chrono_Stopped&#45;&gt;_P_Chrono_Stopped -->
+<g id="edge40" class="edge">
+<title>_P_Chrono_Stopped&#45;&gt;_P_Chrono_Stopped</title>
+<path fill="none" stroke="#000000" d="M479.0221,-444.8676C491.1032,-444.9995 501,-443.377 501,-440 501,-437.6783 496.3222,-436.1859 489.4728,-435.5228"/>
+<polygon fill="#000000" stroke="#000000" points="489.1458,-432.0082 479.0221,-435.1324 488.8845,-439.0033 489.1458,-432.0082"/>
+<text text-anchor="start" x="501" y="-437" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">bottomLeftPressed [INSTATE([&quot;/P/Display/ChronoUpdate&quot;])]^out.resetChrono &#160;&#160;</text>
+</g>
+<!-- _P_Indiglo -->
+<!-- _P_Indiglo_initial -->
+<g id="node31" class="node">
+<title>_P_Indiglo_initial</title>
+<ellipse fill="#000000" stroke="#000000" stroke-width="2" cx="111" cy="-545.5" rx="5.5" ry="5.5"/>
+</g>
+<!-- _P_Indiglo_Off -->
+<g id="node34" class="node">
+<title>_P_Indiglo_Off</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="139,-458 83,-458 83,-422 139,-422 139,-458"/>
+<text text-anchor="start" x="102.9978" y="-436.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Off</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M95.3333,-423C95.3333,-423 126.6667,-423 126.6667,-423 132.3333,-423 138,-428.6667 138,-434.3333 138,-434.3333 138,-445.6667 138,-445.6667 138,-451.3333 132.3333,-457 126.6667,-457 126.6667,-457 95.3333,-457 95.3333,-457 89.6667,-457 84,-451.3333 84,-445.6667 84,-445.6667 84,-434.3333 84,-434.3333 84,-428.6667 89.6667,-423 95.3333,-423"/>
+</g>
+<!-- _P_Indiglo_initial&#45;&gt;_P_Indiglo_Off -->
+<g id="edge42" class="edge">
+<title>_P_Indiglo_initial&#45;&gt;_P_Indiglo_Off</title>
+<path fill="none" stroke="#000000" d="M111,-539.8288C111,-535.1736 111,-528.4097 111,-522.5 111,-522.5 111,-522.5 111,-475.5 111,-473.1079 111,-470.6252 111,-468.1342"/>
+<polygon fill="#000000" stroke="#000000" points="114.5001,-468.0597 111,-458.0598 107.5001,-468.0598 114.5001,-468.0597"/>
+<text text-anchor="middle" x="112.3895" y="-496" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000"> </text>
+</g>
+<!-- _P_Indiglo_Released -->
+<g id="node32" class="node">
+<title>_P_Indiglo_Released</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="216,-204 144,-204 144,-168 216,-168 216,-204"/>
+<text text-anchor="start" x="154.6602" y="-182.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Released</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M156.3333,-169C156.3333,-169 203.6667,-169 203.6667,-169 209.3333,-169 215,-174.6667 215,-180.3333 215,-180.3333 215,-191.6667 215,-191.6667 215,-197.3333 209.3333,-203 203.6667,-203 203.6667,-203 156.3333,-203 156.3333,-203 150.6667,-203 145,-197.3333 145,-191.6667 145,-191.6667 145,-180.3333 145,-180.3333 145,-174.6667 150.6667,-169 156.3333,-169"/>
+</g>
+<!-- _P_Indiglo_Pushed -->
+<g id="node33" class="node">
+<title>_P_Indiglo_Pushed</title>
+<polygon fill="transparent" stroke="transparent" stroke-width="2" points="94,-335 32,-335 32,-299 94,-299 94,-335"/>
+<text text-anchor="start" x="42.657" y="-313.2" font-family="Helvetica,sans-Serif" font-size="12.00" fill="#000000">Pushed</text>
+<path fill="none" stroke="#000000" stroke-width="2" d="M44.3333,-300C44.3333,-300 81.6667,-300 81.6667,-300 87.3333,-300 93,-305.6667 93,-311.3333 93,-311.3333 93,-322.6667 93,-322.6667 93,-328.3333 87.3333,-334 81.6667,-334 81.6667,-334 44.3333,-334 44.3333,-334 38.6667,-334 33,-328.3333 33,-322.6667 33,-322.6667 33,-311.3333 33,-311.3333 33,-305.6667 38.6667,-300 44.3333,-300"/>
+</g>
+<!-- _P_Indiglo_Released&#45;&gt;_P_Indiglo_Pushed -->
+<g id="edge43" class="edge">
+<title>_P_Indiglo_Released&#45;&gt;_P_Indiglo_Pushed</title>
+<path fill="none" stroke="#000000" d="M143.8935,-190.4771C106.6607,-196.1301 54,-207.4863 54,-226.5 54,-273.5 54,-273.5 54,-273.5 54,-278.5369 54.5858,-283.8351 55.4585,-288.9335"/>
+<polygon fill="#000000" stroke="#000000" points="52.0844,-289.898 57.557,-298.97 58.9363,-288.4654 52.0844,-289.898"/>
+<text text-anchor="start" x="54" y="-247" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topRightPressed &#160;&#160;</text>
+</g>
+<!-- _P_Indiglo_Released&#45;&gt;_P_Indiglo_Off -->
+<g id="edge44" class="edge">
+<title>_P_Indiglo_Released&#45;&gt;_P_Indiglo_Off</title>
+<path fill="none" stroke="#000000" d="M216.2666,-196.6114C249.7216,-208.3436 291.6027,-229.1843 273,-256 247.6817,-292.4961 204.7063,-254.5039 179.388,-291 166.9747,-308.8936 172.623,-319.2996 179.388,-340 182.0438,-348.1264 216.055,-368.0758 205,-387 192.8446,-407.808 169.1728,-421.0863 148.6264,-429.1483"/>
+<polygon fill="#000000" stroke="#000000" points="147.3572,-425.8856 139.1579,-432.5954 149.7519,-432.4633 147.3572,-425.8856"/>
+<text text-anchor="start" x="179" y="-314" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">after(2 s)^out.unsetIndiglo &#160;&#160;</text>
+</g>
+<!-- _P_Indiglo_Pushed&#45;&gt;_P_Indiglo_Released -->
+<g id="edge45" class="edge">
+<title>_P_Indiglo_Pushed&#45;&gt;_P_Indiglo_Released</title>
+<path fill="none" stroke="#000000" d="M94.0467,-306.2433C128.7085,-294.1214 180,-275.7958 180,-273.5 180,-273.5 180,-273.5 180,-226.5 180,-222.6152 180,-218.5209 180,-214.4883"/>
+<polygon fill="#000000" stroke="#000000" points="183.5001,-214.1447 180,-204.1447 176.5001,-214.1448 183.5001,-214.1447"/>
+<text text-anchor="start" x="180" y="-247" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topRightReleased &#160;&#160;</text>
+</g>
+<!-- _P_Indiglo_Off&#45;&gt;_P_Indiglo_Pushed -->
+<g id="edge46" class="edge">
+<title>_P_Indiglo_Off&#45;&gt;_P_Indiglo_Pushed</title>
+<path fill="none" stroke="#000000" d="M82.834,-433.5617C68.4735,-428.4357 54,-419.539 54,-404.5 54,-404.5 54,-404.5 54,-357.5 54,-353.4822 54.4273,-349.2925 55.0957,-345.1964"/>
+<polygon fill="#000000" stroke="#000000" points="58.5319,-345.8631 57.1478,-335.3591 51.6794,-344.4337 58.5319,-345.8631"/>
+<text text-anchor="start" x="54" y="-378" font-family="Helvetica,sans-Serif" font-size="10.00" fill="#000000">topRightPressed^out.setIndiglo &#160;&#160;</text>
+</g>
+</g>
+</svg>

+ 206 - 0
examples/digitalwatch/model_digitalwatch.xml

@@ -0,0 +1,206 @@
+<single_instance_cd>
+  <delta>1 ms</delta>
+
+  <statechart>
+    <semantics big_step_maximality="take_many"/>
+
+    <inport name="in">
+      <event name="bottomLeftPressed"/>
+      <event name="bottomLeftReleased"/>
+      <event name="bottomRightPressed"/>
+      <event name="bottomRightReleased"/>
+      <event name="topLeftPressed"/>
+      <event name="topLeftReleased"/>
+      <event name="topRightPressed"/>
+      <event name="topRightReleased"/>
+      <event name="alarmStart"/>
+    </inport>
+
+    <outport name="out">
+      <event name="checkTime"/>
+      <event name="refreshTimeDisplay"/>
+      <event name="refreshChronoDisplay"/>
+      <event name="refreshDateDisplay"/>
+      <event name="refreshAlarmDisplay"/>
+      <event name="resetChrono"/>
+      <event name="startSelection"/>
+      <event name="increaseSelection"/>
+      <event name="selectNext"/>
+      <event name="stopSelection"/>
+      <event name="increaseTimeByOne"/>
+      <event name="increaseChronoByOne"/>
+      <event name="setIndiglo"/>
+      <event name="unsetIndiglo"/>
+      <event name="setAlarm"/>
+    </outport>
+
+    <outport name="out">
+    </outport>
+
+    <root>
+      <parallel id="P">
+        <state id="Indiglo" initial="Off">
+          <state id="Off">
+            <transition event="topRightPressed" target="../Pushed">
+              <raise event="setIndiglo"/>
+            </transition>
+          </state>
+
+          <state id="Pushed">
+            <transition event="topRightReleased" target="../Released"/>
+          </state>
+
+          <state id="Released">
+            <transition event="topRightPressed" target="../Pushed"/>
+            <transition after="2 s" target="../Off">
+              <raise event="unsetIndiglo"/>
+            </transition>
+          </state>
+        </state>
+
+        <state id="Chrono" initial="Stopped">
+          <state id="Stopped">
+            <transition event="bottomLeftPressed" cond='INSTATE(["/P/Display/ChronoUpdate"])' target=".">
+              <raise event="resetChrono"/>
+            </transition>
+            <transition event="bottomRightPressed" cond='INSTATE(["/P/Display/ChronoUpdate"])' target="../Running"/>
+          </state>
+
+          <state id="Running">
+            <transition after="10 ms" target=".">
+              <raise event="increaseChronoByOne"/>
+            </transition>
+            <transition event="bottomRightPressed" cond='INSTATE(["/P/Display/ChronoUpdate"])' target="../Stopped"/>
+          </state>
+        </state>
+
+        <state id="Display" initial="TimeUpdate">
+          <state id="TimeUpdate">
+            <onentry>
+              <raise event="refreshTimeDisplay"/>
+            </onentry>
+            <transition after="1 s" target="."/>
+            <transition event="topLeftPressed" target="../ChronoUpdate"/>
+            <transition event="bottomRightPressed" target="../WaitingToEdit"/>
+            <transition event="bottomLeftPressed" target="../WaitingForAlarm"/>
+          </state>
+
+          <state id="WaitingToEdit">
+            <transition after="1500 ms" target="../EditingTime">
+              <raise event="time_edit"/>
+            </transition>
+            <transition event="bottomRightReleased" target="../TimeUpdate"/>
+          </state>
+
+          <state id="EditingTime" initial="Waiting">
+            <onentry>
+              <raise event="startSelection"/>
+            </onentry>
+            <onexit>
+              <raise event="stopSelection"/>
+            </onexit>
+
+            <state id="Waiting">
+              <transition event="bottomLeftPressed" target="../Increasing"/>
+              <transition event="bottomRightPressed" target="../GoingToNext"/>
+              <transition after="5 s" target="../../TimeUpdate">
+                <raise event="edit_done"/>
+              </transition>
+            </state>
+
+            <state id="GoingToNext">
+              <transition event="bottomRightReleased" target="../Waiting">
+                <raise event="selectNext"/>
+              </transition>
+              <transition after="2 s" target="../../TimeUpdate">
+                <raise event="edit_done"/>
+              </transition>
+            </state>
+
+            <state id="Increasing">
+              <onentry>
+                <raise event="increaseSelection"/>
+              </onentry>
+              <transition after="300 ms" target="."/>
+              <transition event="bottomLeftReleased" target="../Waiting"/>
+            </state>
+          </state>
+
+          <state id="ChronoUpdate">
+            <transition event="topLeftPressed" target="../TimeUpdate"/>
+            <!-- the rendering of the display takes a lot of CPU time (4.25 ms on my machine)
+                 so we don't re-render every 10 ms.. looks good enough -->
+            <transition after="30 ms" target=".">
+              <raise event="refreshChronoDisplay"/>
+            </transition>
+          </state>
+
+          <state id="WaitingForAlarm">
+            <onentry>
+              <raise event="refreshAlarmDisplay"/>
+            </onentry>
+            <transition after="1500 ms" target="../EditingTime">
+              <raise event="alarm_edit"/>
+            </transition>
+            <transition event="bottomLeftReleased" target="../TimeUpdate"/>
+          </state>
+        </state>
+
+        <state id="Alarm" initial="Off">
+          <state id="Off">
+            <transition event="bottomLeftPressed" cond='INSTATE(["/P/Display/TimeUpdate"]) or INSTATE(["/P/Display/WaitingForAlarm"])' target="../On">
+              <raise event="setAlarm"/>
+            </transition>
+          </state>
+
+          <state id="On">
+            <onentry>
+              <raise event="checkTime"/>
+            </onentry>
+            <transition event="bottomLeftPressed" cond='INSTATE(["/P/Display/TimeUpdate"]) or INSTATE(["/P/Display/WaitingForAlarm"])' target="../Off">
+              <raise event="setAlarm"/>
+            </transition>
+            <transition after="1 s" target="."/>
+            <transition event="alarmStart" target="../Blinking"/>
+          </state>
+
+          <state id="Blinking" initial="On">
+            <onexit>
+              <raise event="setAlarm"/>
+              <raise event="unsetIndiglo"/>
+            </onexit>
+            <state id="On">
+              <onentry>
+                <raise event="setIndiglo"/>
+              </onentry>
+              <transition after="500 ms" target="../Off"/>
+            </state>
+            <state id="Off">
+              <onentry>
+                <raise event="unsetIndiglo"/>
+              </onentry>
+              <transition after="500 ms" target="../On"/>
+            </state>
+
+            <transition event="topRightPressed" target="../Off"/>
+            <transition event="topLeftPressed" target="../Off"/>
+            <transition event="bottomRightPressed" target="../Off"/>
+            <transition event="bottomLeftPressed" target="../Off"/>
+          </state>
+        </state>
+
+        <state id="Time" initial="Increasing">
+          <state id="Increasing">
+            <transition after="1 s" target=".">
+              <raise event="increaseTimeByOne"/>
+            </transition>
+            <transition event="time_edit" target="../Editing"/>
+          </state>
+          <state id="Editing">
+            <transition event="edit_done" target="../Increasing"/>
+          </state>
+        </state>
+      </parallel>
+    </root>
+  </statechart>
+</single_instance_cd>

+ 2 - 9
examples/digitalwatch/run.py

@@ -1,17 +1,10 @@
-from sccd.statechart.parser.xml import parse_f, statechart_parser_rules
-from sccd.cd.cd import *
 from sccd.realtime.eventloop import *
 from sccd.realtime.tkinter import TkInterImplementation
-import queue
+from sccd.cd.parser.xml import *
 
 def main():
     # Load statechart
-    g = Globals()
-    sc_rules = statechart_parser_rules(g, "statechart_digitalwatch.xml")
-    statechart = parse_f("statechart_digitalwatch.xml", rules=sc_rules)
-    cd = SingleInstanceCD(g, statechart)
-    g.set_delta(duration(100, Microsecond))
-
+    cd = load_cd("model_digitalwatch.xml")
 
     import tkinter
     from tkinter.constants import NO

+ 0 - 202
examples/digitalwatch/statechart_digitalwatch.xml

@@ -1,202 +0,0 @@
-<statechart>
-  <semantics big_step_maximality="take_many"/>
-
-  <inport name="in">
-    <event name="bottomLeftPressed"/>
-    <event name="bottomLeftReleased"/>
-    <event name="bottomRightPressed"/>
-    <event name="bottomRightReleased"/>
-    <event name="topLeftPressed"/>
-    <event name="topLeftReleased"/>
-    <event name="topRightPressed"/>
-    <event name="topRightReleased"/>
-    <event name="alarmStart"/>
-  </inport>
-
-  <outport name="out">
-    <event name="checkTime"/>
-    <event name="refreshTimeDisplay"/>
-    <event name="refreshChronoDisplay"/>
-    <event name="refreshDateDisplay"/>
-    <event name="refreshAlarmDisplay"/>
-    <event name="resetChrono"/>
-    <event name="startSelection"/>
-    <event name="increaseSelection"/>
-    <event name="selectNext"/>
-    <event name="stopSelection"/>
-    <event name="increaseTimeByOne"/>
-    <event name="increaseChronoByOne"/>
-    <event name="setIndiglo"/>
-    <event name="unsetIndiglo"/>
-    <event name="setAlarm"/>
-  </outport>
-
-  <outport name="out">
-  </outport>
-
-  <root>
-    <parallel id="P">
-      <state id="Indiglo" initial="Off">
-        <state id="Off">
-          <transition event="topRightPressed" target="../Pushed">
-            <raise event="setIndiglo"/>
-          </transition>
-        </state>
-
-        <state id="Pushed">
-          <transition event="topRightReleased" target="../Released"/>
-        </state>
-
-        <state id="Released">
-          <transition event="topRightPressed" target="../Pushed"/>
-          <transition after="2 s" target="../Off">
-            <raise event="unsetIndiglo"/>
-          </transition>
-        </state>
-      </state>
-
-      <state id="Chrono" initial="Stopped">
-        <state id="Stopped">
-          <transition event="bottomLeftPressed" cond='INSTATE(["/P/Display/ChronoUpdate"])' target=".">
-            <raise event="resetChrono"/>
-          </transition>
-          <transition event="bottomRightPressed" cond='INSTATE(["/P/Display/ChronoUpdate"])' target="../Running"/>
-        </state>
-
-        <state id="Running">
-          <transition after="10 ms" target=".">
-            <raise event="increaseChronoByOne"/>
-          </transition>
-          <transition event="bottomRightPressed" cond='INSTATE(["/P/Display/ChronoUpdate"])' target="../Stopped"/>
-        </state>
-      </state>
-
-      <state id="Display" initial="TimeUpdate">
-        <state id="TimeUpdate">
-          <onentry>
-            <raise event="refreshTimeDisplay"/>
-          </onentry>
-          <transition after="1 s" target="."/>
-          <transition event="topLeftPressed" target="../ChronoUpdate"/>
-          <transition event="bottomRightPressed" target="../WaitingToEdit"/>
-          <transition event="bottomLeftPressed" target="../WaitingForAlarm"/>
-        </state>
-
-        <state id="WaitingToEdit">
-          <transition after="1500 ms" target="../EditingTime">
-            <raise event="time_edit"/>
-          </transition>
-          <transition event="bottomRightReleased" target="../TimeUpdate"/>
-        </state>
-
-        <state id="EditingTime" initial="Waiting">
-          <onentry>
-            <raise event="startSelection"/>
-          </onentry>
-          <onexit>
-            <raise event="stopSelection"/>
-          </onexit>
-
-          <state id="Waiting">
-            <transition event="bottomLeftPressed" target="../Increasing"/>
-            <transition event="bottomRightPressed" target="../GoingToNext"/>
-            <transition after="5 s" target="../../TimeUpdate">
-              <raise event="edit_done"/>
-            </transition>
-          </state>
-
-          <state id="GoingToNext">
-            <transition event="bottomRightReleased" target="../Waiting">
-              <raise event="selectNext"/>
-            </transition>
-            <transition after="2 s" target="../../TimeUpdate">
-              <raise event="edit_done"/>
-            </transition>
-          </state>
-
-          <state id="Increasing">
-            <onentry>
-              <raise event="increaseSelection"/>
-            </onentry>
-            <transition after="300 ms" target="."/>
-            <transition event="bottomLeftReleased" target="../Waiting"/>
-          </state>
-        </state>
-
-        <state id="ChronoUpdate">
-          <transition event="topLeftPressed" target="../TimeUpdate"/>
-          <!-- the rendering of the display takes a lot of CPU time (4.25 ms on my machine)
-               so we don't re-render every 10 ms.. looks good enough -->
-          <transition after="30 ms" target=".">
-            <raise event="refreshChronoDisplay"/>
-          </transition>
-        </state>
-
-        <state id="WaitingForAlarm">
-          <onentry>
-            <raise event="refreshAlarmDisplay"/>
-          </onentry>
-          <transition after="1500 ms" target="../EditingTime">
-            <raise event="alarm_edit"/>
-          </transition>
-          <transition event="bottomLeftReleased" target="../TimeUpdate"/>
-        </state>
-      </state>
-
-      <state id="Alarm" initial="Off">
-        <state id="Off">
-          <transition event="bottomLeftPressed" cond='INSTATE(["/P/Display/TimeUpdate"]) or INSTATE(["/P/Display/WaitingForAlarm"])' target="../On">
-            <raise event="setAlarm"/>
-          </transition>
-        </state>
-
-        <state id="On">
-          <onentry>
-            <raise event="checkTime"/>
-          </onentry>
-          <transition event="bottomLeftPressed" cond='INSTATE(["/P/Display/TimeUpdate"]) or INSTATE(["/P/Display/WaitingForAlarm"])' target="../Off">
-            <raise event="setAlarm"/>
-          </transition>
-          <transition after="1 s" target="."/>
-          <transition event="alarmStart" target="../Blinking"/>
-        </state>
-
-        <state id="Blinking" initial="On">
-          <onexit>
-            <raise event="setAlarm"/>
-            <raise event="unsetIndiglo"/>
-          </onexit>
-          <state id="On">
-            <onentry>
-              <raise event="setIndiglo"/>
-            </onentry>
-            <transition after="500 ms" target="../Off"/>
-          </state>
-          <state id="Off">
-            <onentry>
-              <raise event="unsetIndiglo"/>
-            </onentry>
-            <transition after="500 ms" target="../On"/>
-          </state>
-
-          <transition event="topRightPressed" target="../Off"/>
-          <transition event="topLeftPressed" target="../Off"/>
-          <transition event="bottomRightPressed" target="../Off"/>
-          <transition event="bottomLeftPressed" target="../Off"/>
-        </state>
-      </state>
-
-      <state id="Time" initial="Increasing">
-        <state id="Increasing">
-          <transition after="1 s" target=".">
-            <raise event="increaseTimeByOne"/>
-          </transition>
-          <transition event="time_edit" target="../Editing"/>
-        </state>
-        <state id="Editing">
-          <transition event="edit_done" target="../Increasing"/>
-        </state>
-      </state>
-    </parallel>
-  </root>
-</statechart>

+ 13 - 3
src/sccd/cd/globals.py

@@ -12,15 +12,15 @@ class Globals:
     self.events = Namespace()
     self.inports = Namespace()
     self.outports = Namespace()
-    self.durations: List[Duration] = []
+    self.durations: List[SCDurationLiteral] = []
 
     # The smallest unit for all durations in the model.
     # Calculated after all expressions have been parsed, based on all DurationLiterals.
     self.delta: Optional[Duration] = None
 
   # delta: if set, this will be the model delta. otherwise, model delta will be the GCD of all durations registered.
-  def set_delta(self, delta: Optional[Duration]):
-    gcd_delta = gcd(*self.durations)
+  def init_durations(self, delta: Optional[Duration]):
+    gcd_delta = gcd(*(d.d for d in self.durations))
 
     # Ensure delta not too big
     if delta:
@@ -31,6 +31,16 @@ class Globals:
     else:
       self.delta = gcd_delta
 
+    if self.delta != duration(0):
+      # Secretly convert all durations to the same unit...
+      for d in self.durations:
+        d.opt = d.d // self.delta
+    else:
+      for d in self.durations:
+        d.opt = 0
+
+    print_debug("Model delta is %s" % str(self.delta))
+
   def assert_ready(self):
     if self.delta is None:
       raise Exception("Globals not ready: durations not yet processed.")

+ 32 - 0
src/sccd/cd/parser/xml.py

@@ -0,0 +1,32 @@
+from sccd.action_lang.parser import text as action_lang_parser
+from sccd.statechart.parser.xml import *
+from sccd.cd.globals import *
+from sccd.cd.cd import *
+
+def cd_parser_rules(statechart_parser_rules, default_delta = duration(100, Microsecond)):
+  globals = Globals()
+  sc_rules = statechart_parser_rules(globals)
+  delta = default_delta
+
+  def parse_single_instance_cd(el):
+
+    def parse_delta(el):
+      nonlocal delta
+      delta_expr = action_lang_parser.parse_expression(el.text)
+      delta = delta_expr.eval(None)
+
+    def finish_single_instance_cd(statechart):
+      globals.init_durations(delta)
+
+      return SingleInstanceCD(globals, statechart)
+
+    return ([("delta?", parse_delta), ("statechart", sc_rules)], finish_single_instance_cd)
+
+  return [("single_instance_cd?", parse_single_instance_cd)]
+
+# This is usually how you would want to load a class diagram:
+def load_cd(src):
+  import os
+  sc_rules = functools.partial(statechart_parser_rules, path=os.path.dirname(src))
+  cd_rules = cd_parser_rules(sc_rules)
+  return parse_f(src, rules=cd_rules)

+ 2 - 1
src/sccd/controller/controller.py

@@ -99,7 +99,8 @@ class Controller:
         pipe_events = []
         for e in events:
             if isinstance(e.target, InstancesTarget):
-                offset = self._duration_to_time_offset(e.time_offset)
+                # offset = self._duration_to_time_offset(e.time_offset)
+                offset = e.time_offset
                 self.queue.add(self.simulated_time + offset, Controller.EventQueueEntry(e.event, e.target.instances))
             elif isinstance(e.target, OutputPortTarget):
                 assert (e.time_offset == duration(0)) # cannot combine 'after' with 'output port'

+ 12 - 14
src/sccd/render.py

@@ -20,7 +20,7 @@ if __name__ == '__main__':
     args = parser.parse_args()
 
     srcs = get_files(args.path,
-      filter=lambda file: (file.startswith("statechart_") or file.startswith("test_")) and file.endswith(".xml"))
+      filter=lambda file: (file.startswith("statechart_") or file.startswith("test_") or file.startswith("model_")) and file.endswith(".xml"))
 
     if len(srcs):
       if not args.no_svg:
@@ -41,22 +41,20 @@ if __name__ == '__main__':
     def process(src):
       try:
         path = os.path.dirname(src)
-        parse_sc = statechart_parser_rules(Globals(), path, load_external=False)[0][1]
+        parse_sc = statechart_parser_rules(Globals(), path, load_external=False)
 
-        def parse_test(el):
-          def when_done(*statecharts):
-            return statecharts[0]
+        def find_statechart(el):
+          def when_done(statechart):
+            return statechart
           # When parsing <test>, only look for <statechart> node in it.
           # All other nodes will be ignored.
-          return ([("statechart", parse_sc)], when_done)
-
-        statechart = parse_f(src,
-          # Match both <test> and <statechart> root nodes:
-          [
-            ("test?", parse_test),
-            ("statechart?", parse_sc)
-          ],
-          ignore_unmatched=True)
+          return ({"statechart": parse_sc}, when_done)
+
+        statechart = parse_f(src, {
+          "test": find_statechart,
+          "single_instance_cd": find_statechart,
+          "statechart": parse_sc,
+        }, ignore_unmatched=True)
 
         assert isinstance(statechart, Statechart)
 

+ 1 - 1
src/sccd/statechart/cmd/check_model.py

@@ -13,7 +13,7 @@ if __name__ == "__main__":
 
     try:
       path = os.path.dirname(src)
-      rules = statechart_parser_rules(Globals(), path, load_external=True)
+      rules = [("statechart", statechart_parser_rules(Globals(), path, load_external=True))]
 
       statechart = parse(src, rules, decorate_exceptions=(ModelError,))
 

+ 1 - 1
src/sccd/statechart/dynamic/event.py

@@ -33,7 +33,7 @@ class EventTarget(ABC):
 
 # A raised output event with a target and a time offset.
 class OutputEvent:
-    def __init__(self, event: Event, target: EventTarget, time_offset: Duration = duration(0)):
+    def __init__(self, event: Event, target: EventTarget, time_offset: int = (0)):
         self.event = event
         self.target = target
         self.time_offset = time_offset

+ 1 - 1
src/sccd/statechart/dynamic/statechart_instance.py

@@ -93,7 +93,7 @@ class StatechartInstance(Instance):
         raise_nextbs = lambda e, time_offset: self.execution.output.append(OutputEvent(e, InstancesTarget([self]), time_offset))
 
         raise_internal = {
-            InternalEventLifeline.QUEUE: lambda e: raise_nextbs(e, duration(0)),
+            InternalEventLifeline.QUEUE: lambda e: raise_nextbs(e, 0),
             InternalEventLifeline.NEXT_COMBO_STEP: combo_step.add_next_event,
             InternalEventLifeline.NEXT_SMALL_STEP: small_step.add_next_event,
 

+ 3 - 2
src/sccd/statechart/parser/text.py

@@ -16,9 +16,10 @@ class StatechartTransformer(action_lang.ExpressionTransformer):
     super().__init__()
     self.globals: Globals = None
 
+
   # override
-  def duration(self, node):
-    d = action_lang.ExpressionTransformer.duration(self, node)
+  def duration_literal(self, node):
+    d = SCDurationLiteral(node[0])
     self.globals.durations.append(d)
     return d
 

+ 4 - 4
src/sccd/statechart/parser/xml.py

@@ -36,7 +36,7 @@ def statechart_parser_rules(globals, path, load_external = True, parse_f = parse
     else:
       if not load_external:
         raise SkipFile("Parser configured not to load statecharts from external files.")
-      statechart = parse_f(os.path.join(path, ext_file), statechart_parser_rules(globals, path, load_external=False, parse_f=parse_f))
+      statechart = parse_f(os.path.join(path, ext_file), [("statechart", statechart_parser_rules(globals, path, load_external=False, parse_f=parse_f))])
 
     def parse_semantics(el):
       # Use reflection to find the possible XML attributes and their values
@@ -257,7 +257,7 @@ def statechart_parser_rules(globals, path, load_external = True, parse_f = parse
           except Exception as e:
             raise XmlErrorElement(t_el, "Parsing target '%s': %s" % (target_string, str(e))) from e
 
-          def find_state(sequence) -> State:
+          def find_target(sequence) -> State:
             if sequence.data == "relative_path":
               state = transition.source
             elif sequence.data == "absolute_path":
@@ -274,7 +274,7 @@ def statechart_parser_rules(globals, path, load_external = True, parse_f = parse
             return state
 
           try:
-            transition.targets = [find_state(seq) for seq in parse_tree.children]
+            transition.targets = [find_target(seq) for seq in parse_tree.children]
           except Exception as e:
             raise XmlErrorElement(t_el, "Could not find target '%s'." % (transition.target_string)) from e
 
@@ -287,4 +287,4 @@ def statechart_parser_rules(globals, path, load_external = True, parse_f = parse
 
     return ([("semantics?", parse_semantics), ("override_semantics?", parse_semantics), ("datamodel?", parse_datamodel), ("inport*", parse_inport), ("outport*", parse_outport), ("root", parse_root)], finish_statechart)
 
-  return [("statechart", parse_statechart)]
+  return parse_statechart

+ 12 - 0
src/sccd/statechart/static/action.py

@@ -5,6 +5,18 @@ from sccd.action_lang.static.expression import *
 from sccd.action_lang.static.statement import *
 from sccd.statechart.dynamic.event import *
 
+@dataclass
+class SCDurationLiteral(DurationLiteral):
+    opt: Optional[int] = None
+
+    # override
+    def eval(self, memory: MemoryInterface):
+        return self.opt
+
+    # original behavior of eval
+    def as_duration(self):
+        return DurationLiteral.eval(self, None)
+
 @dataclass
 class EvalContext:
     current_state: 'StatechartState'

+ 2 - 2
src/sccd/test/run.py

@@ -7,7 +7,7 @@ from sccd.util.os_tools import *
 from sccd.util.debug import *
 from sccd.cd.cd import *
 from sccd.controller.controller import *
-from sccd.test.parser import *
+from sccd.test.xml import *
 from sccd.util import timer
 
 import sys
@@ -46,7 +46,7 @@ class Test(unittest.TestCase):
       controller = Controller(test.cd)
 
       for i in test.input:
-        controller.add_input(i.event, controller._duration_to_time_offset(i.at))
+        controller.add_input(i.event, i.at.eval(None))
 
       def controller_thread():
         try:

+ 6 - 7
src/sccd/test/parser.py

@@ -6,7 +6,7 @@ from sccd.cd.cd import *
 @dataclass
 class TestInputEvent:
   event: Event
-  at: Duration
+  at: Expression
 
 @dataclass
 class TestVariant:
@@ -17,7 +17,6 @@ class TestVariant:
 
 def test_parser_rules(statechart_parser_rules):
   globals = Globals()
-  sc_rules = statechart_parser_rules(globals)
   input = []
   output = []
 
@@ -30,9 +29,8 @@ def test_parser_rules(statechart_parser_rules):
         time_expr = parse_expression(globals, time)
         time_type = time_expr.init_expr(scope=None)
         check_duration_type(time_type)
-        time_val = time_expr.eval(memory=None)
         input.append(TestInputEvent(
-          event=Event(id=-1, name=name, port=port, params=[]), at=time_val))
+          event=Event(id=-1, name=name, port=port, params=[]), at=time_expr))
 
       return [("event+", parse_input_event)]
 
@@ -59,8 +57,8 @@ def test_parser_rules(statechart_parser_rules):
 
       return [("big_step+", parse_big_step)]
 
-    def when_done(statechart):
-      globals.set_delta(None)
+    def finish_test(statechart):
+      globals.init_durations(delta=None)
       variants = statechart.semantics.generate_variants()
 
       def variant_description(i, variant) -> str:
@@ -89,6 +87,7 @@ def test_parser_rules(statechart_parser_rules):
         output=output)
       for i, variant in enumerate(variants)]
 
-    return (sc_rules + [("input?", parse_input), ("output?", parse_output)], when_done)
+    sc_rules = statechart_parser_rules(globals)
+    return ([("statechart", sc_rules), ("input?", parse_input), ("output?", parse_output)], finish_test)
 
   return [("test", parse_test)]